云计算百科
云计算领域专业知识百科平台

构建一个最简单的UDP服务器和客户端并逐行解析

目录

1.服务器

(1)基本概念

(2)代码实现

 3.逐行解析

1)

2)

3)

4)

5)

6)

7)

8)

1. response.getBytes():

2.response.getBytes().length: 

3.requestPacket.getSocketAddress(): 

4.DatagramPacket responsePacket = new DatagramPacket 

9)

10)

11)

2.客户端

(1)基本概念

(2)代码实现

(3)逐行解析

1)

2)

3)

4)

5)

6)

7)

8)

9)

10)

3.结果展示


在 Java 网络编程中,客户端(Client)和服务器(Server)是两个核心角色,它们共同构成了网络通信的基本模型(即 C/S 架构)。

以下我会逐行解析构建一个最简单的服务器和客户端的代码。

1.服务器

(1)基本概念

服务器是 接收请求 的一方,被动监听特定端口,处理客户端请求并返回响应。 典型场景:Web 服务器(如 Tomcat)、数据库服务器、游戏服务器等。

(2)代码实现

public class UdpEchServer {
private DatagramSocket socket=null;
public UdpEchServer(int port) throws SocketException {
socket=new DatagramSocket(port);
}
public void start() throws IOException {
System.out.println("服务器启动");
while(true){
/*
1.读取请求并解析
*/
DatagramPacket requestPacket=new DatagramPacket(new byte[4096],4096);
socket.receive(requestPacket);
String request=new String(requestPacket.getData(),0,requestPacket.getLength());//数组中有效的长度,避免只收到很少的数据却构建了很大的byte数组
//2.根据请求,计算相应(一个服务器最关键的逻辑)
String response=process(request);

/*3.将响应返回给客户端*/
DatagramPacket responsePacket = new DatagramPacket(response.getBytes(),response.getBytes().length,requestPacket.getSocketAddress());
socket.send(responsePacket);
//4.打印一个日志
System.out.printf(
"[%s:%d] request:%s, response:%s\\n",
requestPacket.getAddress().toString(), // 客户端IP地址
requestPacket.getPort(), // 客户端端口号
request, // 请求内容
response // 响应内容
);
}
}
/*把根据请求计算响应的逻辑构建成了一个方法 */
private String process(String request) {
return request;
}
public static void main(String[] args) throws IOException {
UdpEchoClient client = new UdpEchoClient("127.0.0.1", 9090);
client.start();
}
}

 3.逐行解析

1)

private DatagramSocket socket=null;

DatagramSock是UDP socket ,用于发送和接受数据包。

2)

public UdpEchServer(int port) throws SocketException {
socket=new DatagramSocket(port);
}

指定一个端口号(int port)给服务器使用。因为服务器的端口号不能一直变,所以直接指定固定端口号。

3)

while(true)

因为服务器通常是7*24小时不间断的读取请求的,所以通常会用一个while(true)这样的死循环来保证服务器持续工作。循环一次,就相当于读取一次请求。

4)

DatagramPacket requestPacket=new DatagramPacket(new byte[4096],4096);

构建出一个用于接受请求数据报的DatagramPacket。

这里使用构造函数 DatagramPacket(byte[] buf, int length) 创建了一个 DatagramPacket 对象,其中:

  • byte[] buf 是用于存储接收到的数据的缓冲区。
  • int length 是缓冲区的长度,表示可以接收的最大数据量。

5)

socket.receive(requestPacket);

 这里将requestPacket作为输出型参数:

  • 这一行代码是使用UDP套接字接收数据报的方法调用。receive方法会阻塞服务器进程,直到接收到一个数据报。
  • 一旦接收到数据报,requestPacket将被填充接收到的数据、发送方的IP地址和端口号。

6)

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

将读取到的二进制数据转换成字符串:

  • requestPacket.getData(): 这个方法调用返回的是接收到的数据包中包含的字节数组。这个数组的大小是固定的(在此例中为4096字节),但其中只有部分是实际接收到的数据,所以还需要指定字节数组的有效长度。

  • requestPacket.getLength(): 这个方法调用返回的是实际接收到的数据的长度,也就是有效长度。由于UDP数据包的大小是固定的,而实际传输的数据可能较少,因此getLength()的值可能小于getData().length。这个方法确保只处理实际接收到的数据,而不是整个4096字节的数组。

  • 0: 这是字节数组的偏移量,表示从数组的第0个位置开始读取数据。

  • new String(…): 这是一个构造函数调用,用于将字节数组转换为字符串。这里使用的是特定范围的字节数组(从偏移量0开始,长度为requestPacket.getLength())来创建字符串,而不是整个数组。

  • 7)

    String response=process(request);

    这一段代码的含义是根据请求来作出响应,一般来说是一个服务器最关键的逻辑,但是此处的服务器是回显服务器,所以这个逻辑被省略了。

    可以response=request,但是此处将做出相应的逻辑构建成了一个process方法,方便后续做其他服务器:

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

    8)

    DatagramPacket responsePacket = new
    DatagramPacket(response.getBytes(),response.getBytes().length,
    requestPacket.getSocketAddress());

    再次构建一个DatagramPacket对象作为发送给客户端的数据报:responsePacket。

    1. response.getBytes():

    • 这个方法将 前面接受reqest后得到的String 类型的 response 转换为 byte[] 类型的数组。
    • getBytes() 方法会根据平台的默认字符集将字符串编码为字节数组。

    2.response.getBytes().length: 

    • 这里调用了 response.getBytes() 方法得到的字节数组的长度。
    • 这个长度表示实际响应数据的总字节数,确保发送的数据报中只包含有效的响应内容。

    长度要用response.getBytes().length,因为response是字符串,需要先转成二进制数组,才能获取到数组的长度
    不能用response.length,因为response是字符串,字符串的长度是字符的个数,而不是二进制数组的长度

    3.requestPacket.getSocketAddress(): 

    • 这个方法用于获取发送请求的数据报(requestPacket)的源地址(SocketAddress)。
    • SocketAddress 包含了客户端的 IP 地址和端口号信息,这样服务器就能知道将响应数据发送回哪个客户端。

     

    4.DatagramPacket responsePacket = new DatagramPacket 

    • 这里创建了一个新的 DatagramPacket 对象,命名为 responsePacket。
    • 构造函数 DatagramPacket(byte[] buf, int length, SocketAddress address) 的参数分别为:
      • byte[] buf: 要发送的数据的字节数组。
      • int length: 数据的有效长度。
      • SocketAddress address: 目标地址,即要发送到的客户端地址。

    9)

    socket.send(responsePacket);

    发送数据包给客户端,由于前面使用了requestPacket.getSocketAddress()方法将源ip、源端口号都传给了requestPacket,所以此处UDP已经知道了该发送给谁。

    10)

    System.out.printf(
    "[%s:%d] request:%s, response:%s\\n",
    requestPacket.getAddress().toString(), // 客户端IP地址
    requestPacket.getPort(), // 客户端端口号
    request, // 请求内容
    response // 响应内容
    );

    打印一个日志,方便调试和监控。

    11)

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

     在main方法中实例化服务器,并指定了服务器的端口号是9090。

    2.客户端

    (1)基本概念

    客户端是 发起请求 的一方,主动连接服务器并发送请求,然后等待服务器的响应。 典型场景:浏览器、移动应用、桌面程序等。

    (2)代码实现

    public class UdpEchoClient {
    private DatagramSocket socket = null;
    //UDP本身不保存对方信息,在自己的代码中保存一下
    private String sercerIp;
    private int serverPort;

    //和服务器不同,客户端的构造方法不能只有一个端口号,还要有ip地址
    public UdpEchoClient(String sercerIp, int serverPort) throws SocketException {
    this.sercerIp = sercerIp;
    this.serverPort = serverPort;
    //创建一个socket,不能传入端口号,因为端口号会有竞争,让系统随机分配一个空闲的即可
    socket = new DatagramSocket();
    }

    //启动客户端
    public void start() throws IOException {
    Scanner sc = new Scanner(System.in);
    while (true) {
    //1.读取用户输入的数据
    System.out.println("请输入要发送的数据");
    String request = sc.next();
    //2.将请求发送给服务器,构建一个DatagramPacket对象,发送给服务器
    DatagramPacket packet = new DatagramPacket(request.getBytes(), request.getBytes().length, InetAddress.getByName(sercerIp), serverPort);
    //3.发送数据
    socket.send(packet);
    //4.接收服务器的响应数据
    DatagramPacket responsePacket = new DatagramPacket(new byte[4096], 4096);
    socket.receive(responsePacket);
    //5.从数据包中获取响应数据,打印出来
    String response = new String(responsePacket.getData(), 0, responsePacket.getLength());
    System.out.println("response:" + response);
    }
    }

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

    (3)逐行解析

    1)

    private DatagramSocket socket = null;

    创建一个socket用来接收和发送数据

    2)

    private String sercerIp;
    private int serverPort;

    定义String类型的ip地址和int 类型的端口号。

    3)

    public UdpEchoClient(String sercerIp, int serverPort) throws SocketException {
    this.sercerIp = sercerIp;
    this.serverPort = serverPort;
    //创建一个socket,不能传入端口号,因为端口号会有竞争,让系统随机分配一个空闲的即可
    socket = new DatagramSocket();
    }

    创建客户端的构造方法。与服务器不同的是,参数不止有端口号,还有ip地址,因为客户端要知道服务器的ip地址和端口号以便发送,而服务器只需要一个端口号来监听、接受客户端发送来的数据。

    4)

    //1.读取用户输入的数据
    System.out.println("请输入要发送的数据");
    String request = sc.next();

    读取用户输入的数据。

    5)

    DatagramPacket packet = new
    DatagramPacket(request.getBytes(), request.getBytes().length,
    InetAddress.getByName(sercerIp), serverPort);

    将请求发送给服务器:构建一个DatagramPacket对象来发送。

    1.request.getBytes()

    来将字符串request中的字节数组取出来。

    2.request.getBytes().length

    指定字节数组的长度

    3.InetAddress.getByName(sercerIp), serverPort

    传入服务器的ip地址和端口号,其中ip地址是字符串,需要用getByname()方法来包装一下。

    6)

    socket.send(packet);

     发送数据给服务器。

    7)

    DatagramPacket responsePacket = new DatagramPacket(new byte[4096], 4096);

    构建一个DatagramPacket对象来作为服务器的响应数据

    8)

    socket.receive(responsePacket);

    responsePacket作为输出型参数,得到了响应数据包里面的内容。

    9)

    String response = new String(responsePacket.getData(), 0, responsePacket.getLength());
    System.out.println("response:" + response);

    用getData()方法得到的字节数组构建一个字符串作为响应数据,指定了字节数组的长度为【0,字节数组的长度)。

    打印日志。

    10)

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

    在main方法中指定服务器的ip地址是“127.0.0.1”,这是一个环回ip,表示本机。指定服务器的端口号9090,与服务器的端口号对应。

    3.结果展示

    服务器: 

    客户端: 

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » 构建一个最简单的UDP服务器和客户端并逐行解析
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!