Java中的UDP通信

2023-10-16 11:01:14 浏览数 (1)

1 UDP通信机制

Internet 协议集支持一个无连接的传输协议,该协议称为用户数据报协议(UDP,User Datagram Protocol)。与TCP协议不同,UDP 为应用程序提供了一种无需建立连接就可以发送封装的 IP 数据包的方法。在发送数据前,需要进行封包操作(使用 DatagramPacket 类),才能发送和接收数据(使用 DatagramSocket 类)。

使用UDP传输数据时,可能存在的问题有:

丢失包;

乱序;

错误包;

数据包的重复发送。

通常需要使用UDP的场景主要是对数据流要求不高时,如视频流、音频流等。

2 UDP 通信编程的一般步骤

  • 创建客户端的 DatagramSocket 并定义客户端用来接收报文的端口;
  • 创建服务器端的 DatagramSocket 并定义服务端用来接收报文的端口;
  • 在服务器端创建 DatagramPacket 对象,封装待发送的数据包;
  • 客户端发送报文;
  • 服务器端接收报文。

3 服务端

服务端接收数据使用 DatagramSocket对象,创建对象时,需要指定一个用于接收请求的端口。

代码语言:javascript复制
import java.net.DatagramPacket;
import java.net.DatagramSocket;

public class UdpServer {
    public static void main(String[] args) {
        try {
            //创建服务端接收数据的 DatagramSocket 对象
            DatagramSocket datagramSocket = new DatagramSocket(5555);
            //创建数据缓冲区
            byte[] buff = new byte[1024];
            //创建数据报的包对象
            DatagramPacket packet = new DatagramPacket(buff, buff.length);
            //等待接收客户端发送的数据
            datagramSocket.receive(packet);
            //获取数据
            String input = new String(packet.getData(), 0, packet.getLength());

            System.out.println("接收到客户端的请求: "   input);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

在接收客户端发来的请求时,使用了字节缓冲区,可以一次性接收 1024 个字节的数据,可以减少网络IO的操作。

在服务端和客户端之间的数据流使用 DatagramPacket 封装,因此在接收数据时,应使用该对象进行接收。

datagramSocket.receive(packet);方法是一个阻塞式方法,当没有接收到数据时,程序将在这里等待,接收到数据后,才会继续执行下边的代码。

在接收到字节数据后,如果不想直接使用二进制数据,需要对数据进行转换。

在获取接收到的数据时,使用的是 new String(packet.getData(), 0, packet.getLength()) ,并没有读取缓冲区的所有内容,因为当从网卡中读取的实际数据,若长度小于缓冲区长度时,其数据对于服务端来说是没有意义的。我们仅需要拿走实际接收到的数据报即可。

4 客户端

创建客户端时,也需要创建一个 DatagramSocket 对象,同时指定发送数据的端口,如果和服务端在同一台机器上时,该端口应与服务端不同。

在客户端发送数据时,需要将数据封装到 DatagramPacket 对象中,同时需要指定接收数据的服务端IP及端口。

代码语言:javascript复制
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.util.Scanner;

public class UdpClient {
    public static void main(String[] args) {
        try {
            //创建数据发送对象,并指定要发送数据的端口
            DatagramSocket socket = new DatagramSocket(5556);
            //将要发送的数据转换为字节数组
            Scanner scanner = new Scanner(System.in);
            String output = scanner.next();
            byte[] bytes = output.getBytes();
            //创建数据报的包对象
            DatagramPacket packet = new DatagramPacket(bytes, bytes.length, new InetSocketAddress("127.0.0.1", 5555));
            //发送消息
            socket.send(packet);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

5 通信

5.1 不启动服务端

当没有启动服务端,只启动客户端发送数据时,客户端将数据正常发出而没有报错。

可见客户端在发送数据时,并没有对服务端进行检查。

5.2 启动服务端

这是一次通信,如果想要建立多次通信,可以在服务端加上循环,方法同 TCP 通信类似。

0 人点赞