2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
Socket APIs are all provided by the system. Different systems provide different APIs, but Java further encapsulates these system APIs.
The socket API in UDP focuses on two classes: DatagramSocket and DatagramPacket
The role of this class can be seen as a remote control for "operating the network card", that is, reading and writing operations on the network card, which can be understood as reading and writing files.
Several methods are provided:
This class describes UDP datagrams. A DatagramPacket object is equivalent to a UDP datagram. Sending and receiving once means transmitting a DatagramPacket object.
Echo: When the client sends different requests to the server, the server will return different responses. But in this case, the echo means that the server responds to the client's request without any calculation or business logic.
public class udpEchoServer {
public DatagramSocket socket = null;
public udpEchoServer(int port) throws SocketException {
socket = new DatagramSocket(port);
}
public void start() throws IOException {
System.out.println("服务器启动!!!");
while (true) {
//接受客户端请求
DatagramPacket requestPacket = new DatagramPacket(new byte[4096],4096);
socket.receive(requestPacket);
//为了更好处理数据并方便打印,将接受的数据转化为字符串操作
String request = new String(requestPacket.getData(),0,requestPacket.getLength());
//处理客户端的请求(算术计算或者业务逻辑)
String response = this.process(request);
//将处理完的请求返还给客户端
DatagramPacket resposePacket = new DatagramPacket(response.getBytes(),0,response.getBytes().length,
requestPacket.getSocketAddress());
socket.send(resposePacket);
//打印客户端的ip地址端口号和接收客户端的数据以及处理完客户端后的数据
System.out.printf("[%s:%d] req = %s,resp = %sn",requestPacket.getAddress(),requestPacket.getPort(),
request,response);
}
}
public String process(String request) {
return request;
}
public static void main(String[] args) throws IOException {
udpEchoServer udpEchoServer = new udpEchoServer(9999);
udpEchoServer.start();
}
}
The DatagramPacket object represents a datagram. A UDP datagram consists of a header and a payload. The IP address and port number in the header are attributes of the DatagramPacket class. The payload is not provided by this class, so the programmer needs to provide it himself. Just like a monk begging for alms, you need to provide a bowl for begging, and then each family puts the food in the bowl. Since the essence of a datagram is binary data, I provide a byte array to store data as the payload.
The data received from the client needs to be returned to the client after being processed by the server, so a DatagramPacket object needs to be created to store the data processed by the server before the server sends it to the client. At this time, the DatagramPacket object does not need to provide a blank space, just put the processed data into this object. Since the client's IP address and port number are recorded when receiving the data, when sending it to the client, you only need to obtain the client's IP address and port number through requestPacket.getSocketAddress().
Since the server is fixed, you can set the port number directly yourself. The port number is created when the server is started.
Why do we need port numbers and IP addresses?
To achieve successful communication between the two parties, these four core indicators must be met:
Source port, source IP, destination port, destination IP
Through these four core indicators, network communication between the two parties can be achieved. There is no server IP address here because the client and server are on the same host. We can use an IP to represent 172.0.0.1, also known as the loopback IP.
public class udpEchoClient {
private DatagramSocket socket = null;
private String serverIp;
private int serverProt;
public udpEchoClient(String serverIp, int serverProt) throws SocketException {
socket = new DatagramSocket();
this.serverIp = serverIp;
this.serverProt = serverProt;
}
public void start() throws IOException {
System.out.println("客户端启动!");
//1.从控制台获取字符串
Scanner scanner = new Scanner(System.in);
while(true) {
System.out.println("请输入要发送的请求: ");
String request = scanner.nextLine();
//2.将输入的字符串发送给服务器,还要将发送的目标确定,IP和端口号
DatagramPacket requestPacket = new DatagramPacket(request.getBytes(), 0, request.getBytes().length,
InetAddress.getByName(serverIp), serverProt);
socket.send(requestPacket);
//3.从服务器读取到经过处理的响应
DatagramPacket responsePackt = new DatagramPacket(new byte[4096], 4096);
socket.receive(responsePackt);
//将响应打印在控制台
String response = new String(responsePackt.getData(), 0, responsePackt.getLength());
System.out.println(response);
}
}
public static void main(String[] args) throws IOException {
udpEchoClient udpEchoClient = new udpEchoClient("127.0.0.1",9999);
udpEchoClient.start();
}
}
The requestPacket object obtains the reference and length of the string received from the console, as well as its own IP and Prot, and then sends it to the server through the socket's send method.
To receive the response from the server, you need to create a responsePackt object and create a blank byte array in advance to receive the response received from the server.
Let’s distinguish some methods:
Before distinguishing the methods, we need to understand the concepts of bytes, characters, and encoding forms.
Bytes and characters are essentially binary, which is data like 0101, because computers only recognize 0101.
Byte: Byte is the basic unit of computer data storage. 1 byte is 8 bits, each bit can be 0 or 1, which means that a byte can represent 256 different values.
Character: Character is the basic unit for representing text information. Depending on the encoding format, the number of bytes corresponding to one character will vary. Through the encoding format, characters can be converted into bytes and then bytes can be used to represent, transmit and store data.
Encoding format:
The method is different:
Here we can apply the idea of inheritance and polymorphism to implement this server, because the essential difference between this dictionary translation server and the echo server is the processing of responses, so we can inherit and reuse the repeated code and expand the required code.
public class udpDictServer extends udpEchoServer{
HashMap<String,String> map = null;
public udpDictServer(int port) throws SocketException {
super(port);
map = new HashMap<>();
map.put("server","服务");
map.put("client","客户端");
map.put("cat","🐱");
map.put("dog","🐕");
map.put("pig","🐖");
}
@Override
public String process(String request) {
return map.getOrDefault(request, "该词汇没有查询到");
}
public static void main(String[] args) throws IOException {
udpDictServer udpDictServer = new udpDictServer(9999);
udpDictServer.start();
}
}
To implement this dictionary translation, we also need a map in the data structure and use the key-value pairs in the map to store data.
Then the specific business operations only need to rewrite the process method.
When executing here, although this refers to the udpEchoServer object of the parent class, the udpDictServer subclass inherits the udpEchoServer parent class and has rewritten the process method. Due to the polymorphic nature, the process method executed is actually the process method of the subclass.