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:
- Initialize first
- Enter the main cycle
a) Read request and parse
b) Calculate response based on request
c) Write the response back to the client
.
client:
- Initialize first
- 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:
- DatagramSocket API
Datagram socket is a UDP Socket used to send and receive UDP datagrams
- Datagram socket construction method:
Method signature | Method 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 signature | Method 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 |
- DatagramPacket API
Datagram packet is the datagram sent and received by UDP Socket
- Datagram packet construction method:
Method signature | Method 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 signature | Method 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 |
- InetSocketAddress API
- Inetsocketaddress (subclass of socketaddress) construction method:
Method signature | Method description |
---|---|
InetSocketAddress(InetAddress addr, int port) | Create a Socket address, including IP address and port number |