Simple server UDP version, familiar with its API [network]

Posted by fxb9500 on Tue, 04 Jan 2022 17:09:20 +0100

By writing a simple server to understand the common API s of UDP

Datagram oriented (sending and receiving data must be transmitted in a certain packet)
Use transport layer UDP protocol

UDP server program

For a server program, the core process is divided into two steps:
1. Initialization (instantiate Socket object)
2. Enter the main loop, receive and process the request (the main loop is an "dead loop")

  • a) Read data and parse
  • b) Calculate response based on request
  • c) Write the response results to the client

Take an echo server as an example:
Simplest client server
The client sends a string to the server, and the server returns the string intact (echo server)
Equivalent to "Hello World!" in server development

1. Initialization:

private DatagramSocket socket = null;

// Construction method
public UdpEchoServer(int port) throws SocketException {
    socket = new DatagramSocket(port);
}

The construction method here is to new a socket object
When the socket object is new, the current socket object will be associated with an IP address and a port number (binding port)
.
When constructing a socket, if no IP is written, it defaults to 0.0.0.0 (special IP), which will be associated with the IP of all network cards of the host. Generally, the write server uses all 0IP
socket object is essentially a file; This file is an abstraction of the network card

2. Receive and process requests in the main loop

  • ① Read data and parse
DatagramPacket requestPacket = new DatagramPacket(new byte[4096],4096);
// A DatagramPacket object is created and a buffer is associated with the object

socket.receive(requestPacket); 

String request = new String(requestPacket.getData(),
        0, requestPacket.getLength()).trim();

Datagram packet is the datagram sent and received by UDP Socket
As soon as the program starts, it can be executed to receive
.
Think: after the server is started, does the client send a request??
A: No, when the client sends the request is uncertain
In the case of high probability, when the receive is called, the client has not sent any data. At this time, the receive operation will block and wait until there is data; When the data from the client comes, the receive will put the received data into the buffer of the datagram packet object

String request = new String(requestPacket.getData(),
        0, requestPacket.getLength()).trim();

Here is to convert the request data into a String (originally, the request was a byte [])
Reason for calling the trim method of String: the data actually sent by the user may be far less than 4096, and the length obtained by getLength here is 4096. Unnecessary white space characters can be "dried" through trim~

  • ② Calculate response based on request
String response = process(request);

public String process(String request) {
    return request;
}

Since this is an echo server, the request content is what the response content is
If it is a more complex server, it needs to include more business logic to carry out specific operations

  • ③ Write the response results to the client
DatagramPacket responsePacket = new DatagramPacket(response.getBytes(),
        response.getBytes().length,requestPacket.getSocketAddress());
        
socket.send(responsePacket);

The response data is the response, which needs to be wrapped into a packet object
.
response.getBytes( ).length, which cannot be written as response Length(), so the number of characters is obtained;
The correct way is to get the number of bytes
.
requestPacket.getSocketAddress() indicates who the package will be sent to later (who is the destination IP and port?), The address here is the port and address of the client, which are contained in the requestpacket

If packet is used for receive, just specify buffer (address is filled by kernel when receiving data)
If the packet is used for send, in addition to specifying the buffer, you also need to specify who to send to (manually set by the user)
Setting method:
① Directly set the InetAddress object (which contains both IP and port)
② Set IP and port separately

Full code:

// The server
public class UdpEchoServer {
    private DatagramSocket socket = null;

    // The construction method here is to new a socket object
    public UdpEchoServer(int port) throws SocketException {
        socket = new DatagramSocket(port);
    }

    // Start the server
    public void start() throws IOException {
        System.out.println("Server startup!");
        while (true){
            // a) Read data and parse
            DatagramPacket requestPacket = new DatagramPacket(new byte[4096],4096); 
            socket.receive(requestPacket); // As soon as the program starts, it can be executed to receive
            String request = new String(requestPacket.getData(),
                    0, requestPacket.getLength()).trim();
            // b) Calculate response based on request
            String response = process(request);
            // c) Write the response results to the client
            DatagramPacket responsePacket = new DatagramPacket(response.getBytes(),
                    response.getBytes().length,requestPacket.getSocketAddress());
            socket.send(responsePacket);

            // Print an output log
            System.out.printf("[%s:%d] req: %s,resp: %s\n",
                    requestPacket.getAddress().toString(),
                    requestPacket.getPort(),
                    request,
                    response);
        }
    }

    public String process(String request) {
        // Since this is an echo server, the request content is what the response content is
        return request;
    }

    public static void main(String[] args) throws IOException {
        UdpEchoServer server = new UdpEchoServer(6060);
        server.start();
    }
}

UDP client program

The main process of the client is divided into four steps:
1. Read the input data from the user
2. Send the construction request to the server
3. Read the response from the server
4. Write the response back to the client

private DatagramSocket socket = null;
private String serverIP;
private int serverPort;

// You need to specify which server to connect to when starting the client
public UdpEchoClient(String serverIP,int serverPort) throws SocketException {
    this.serverIP = serverIP;
    this.serverPort = serverPort;
    // When constructing the socket of the client, the port number does not need to be bound
    socket = new DatagramSocket();
}

The server must bind the port number
The client must not bind the port number (an idle port is automatically assigned by the operating system)
Usually, a port number can only be bound by one process
After the server binds the port, the client can access it
Reason why the client cannot be bound: if the client is bound, only one client can be started on a host

1. Read the input data from the user

Scanner scan = new Scanner(System.in);

System.out.println("-> ");
String request = scan.nextLine();
if(request.equals("exit")){
    break;
}

2. The client sends the construction request to the server

DatagramPacket requestPacket = new DatagramPacket(request.getBytes(),
        request.getBytes().length, InetAddress.getByName(serverIP),serverPort);
socket.send(requestPacket);

3. Read the response from the server

DatagramPacket responsePacket = new DatagramPacket(new byte[4096],4096);
socket.receive(responsePacket);
String response = new String(responsePacket.getData(),0,responsePacket.getLength()).trim();

This code is as like as two peas for the server to read the request code.

4. Explicit response data

System.out.println(response);

Full code:

// client
public class UdpEchoClient {
    private DatagramSocket socket = null;
    private String serverIP;
    private int serverPort;

    // You need to specify which server to connect to when starting the client
    public UdpEchoClient(String serverIP,int serverPort) throws SocketException {
        this.serverIP = serverIP;
        this.serverPort = serverPort;
        // When constructing the socket of the client, the port number does not need to be bound
        socket = new DatagramSocket();
    }

    public void start() throws IOException {
        Scanner scan = new Scanner(System.in);
        while (true){
            // 1. Read the input data from the user
            System.out.println("-> ");
            String request = scan.nextLine();
            if(request.equals("exit")){
                break;
            }
            // 2. The client sends the construction request to the server
            DatagramPacket requestPacket = new DatagramPacket(request.getBytes(),
                    request.getBytes().length, InetAddress.getByName(serverIP),serverPort);
            socket.send(requestPacket);
            // 3. Read the response from the server
            DatagramPacket responsePacket = new DatagramPacket(new byte[4096],4096);
            socket.receive(responsePacket);
            String response = new String(responsePacket.getData(),0,responsePacket.getLength()).trim();
            // 4. Write the response back to the client explicit response data
            System.out.println(response);
        }
    }

    public static void main(String[] args) throws IOException {
        UdpEchoClient client = new UdpEchoClient("127.0.0.1",6060);
        client.start();
    }
}

Supplement:
127.0.0.1 is a special IP - loopback IP, which can access itself
The server and client are on the same host, and the IP written by the client is the loopback IP
If it is not on the same host, the IP here should be written as the server IP

6060. This port should match the port bound by the server

Understanding quintuples from a client perspective

Protocol type: UDP
Source IP: IP of the client (host IP of the client)
Source port: the port of the client (the port automatically assigned by the operating system)
Destination IP: server IP (if the server and client are on the same host, the IP is 127.0.0.1)
Destination port: 6060 (the port bound when the server starts)

Run Demo:
Run the server program and the client program at the same time



When you start the client again, you will find that the port number of the client has changed~


Purpose of network programming: cross host communication
However, there is no cross host at this time

summary

The server:

  1. Initialize first
  2. Enter the main cycle
    a) Read request and parse
    b) Calculate response based on request
    c) Write the response back to the client
    .

client:

  1. Initialize first
  2. Enter the main cycle
    a) Read user input
    b) Construct the request and send it to the server
    c) Read server response
    d) Display the response on the interface

Drawing understanding:


be careful:
Constructed packet object,
If it is used for receive, only the buffer can be specified (the address is filled by the kernel when receiving data)
If it is used for send, in addition to specifying the buffer, you also need to specify who to send to (set manually by the user and specify the IP)

If the receive d data is larger than the size of the buffer:
For UDP: the data will be truncated (the extra data will be gone ~)

Method summary:

  1. DatagramSocket API

Datagram socket is a UDP Socket used to send and receive UDP datagrams

  • Datagram socket construction method:
Method signatureMethod description
DatagramSocket( )Create a Socket of UDP datagram Socket and bind it to any random port of the machine (generally used for the client)
DatagramSocket(intport)Create a Socket of UDP datagram Socket and bind it to the port specified locally (generally used for the server)
  • Datagram socket method:
Method signatureMethod description
void receive(DatagramPacket p)Receive datagrams from this socket (if no datagrams are received, the method blocks waiting)
void send(DatagramPacketp)Send datagram packets from this socket (no blocking wait, send directly)
void close( )Close this datagram socket
  1. DatagramPacket API

Datagram packet is the datagram sent and received by UDP Socket

  • Datagram packet construction method:
Method signatureMethod description
DatagramPacket (byte[ ]buf, int length)Construct a datagram packet to receive datagrams. The received data is stored in the byte array (the first parameter buf) and receives the specified length (the second parameter length)
DatagramPacket (byte[ ]buf, int offset, int length,SocketAddress address)Construct a datagram packet to send datagrams. The sent data is from 0 to the specified length (the second parameter length) in the byte array (the first parameter buf), and address specifies the IP and port number of the destination host
  • Datagram packet method:
Method signatureMethod description
InetAddressgetAddress()Obtain the sending end host IP address from the received datagram; Or obtain the host IP address of the receiving end from the sent datagram
int getPort( )Obtain the port number of the sending end host from the received datagram; Or obtain the host port number of the receiving end from the sent datagram
byte[ ] getData( )Get data in datagram
  1. InetSocketAddress API
  • Inetsocketaddress (subclass of socketaddress) construction method:
Method signatureMethod description
InetSocketAddress(InetAddress addr, int port)Create a Socket address, including IP address and port number

Topics: Java network server udp