Java网络:UDP DatagramSocket

时间:2020-01-09 10:36:14  来源:igfitidea点击:

DatagramSocket是Java的通过UDP(而非TCP)进行网络通信的机制。 UDP仍位于IP之上。我们可以使用Java的DatagramSocket来发送和接收UPD数据报。

UDP与TCP

UDP的工作原理与TCP略有不同。通过TCP发送数据时,首先要创建一个连接。一旦建立了TCP连接,TCP就会保证数据到达另一端,否则它将告诉我们发生了错误。

使用UDP,我们只需将数据包(数据报)发送到网络上的某个IP地址。我们不能保证数据会到达。我们也无法保证UDP数据包到达接收方的顺序。这意味着UDP比TCP具有更少的协议开销(无流完整性检查)。

UDP适用于数据传输,在传输过程中是否丢失数据包并不重要。例如,想象一下通过互联网传输实况电视信号。我们希望信号尽可能接近现场。因此,如果丢失了一两帧,则不必担心。我们不希望延迟直播,只是确保所有帧都在客户端显示。我们宁愿跳过错过的帧,并始终直接移至最新的帧。

监视摄像机通过互联网广播也可能是这种情况。当我们尝试监视当前时,谁会关心过去发生的事情。我们不想只因为要向监视相机的人显示所有画面而最终落后现实30秒。摄像机记录的存储有些不同。将图像从相机录制到磁盘时,我们可能不想丢掉一帧。我们可能希望稍微延迟一下,而不要让那些帧退回去检查是否发生了重要的事情。

通过DatagramSocket发送数据

要通过Java的DatagramSocket发送数据,我们必须首先创建一个DatagramPacket。这是完成的方式:

byte[] buffer = new byte[65508];
InetAddress address = InetAddress.getByName("Hyman.com");

DatagramPacket packet = new DatagramPacket(
    buffer, buffer.length, address, 9000);

字节缓冲区(字节数组)是要在UDP数据报中发送的数据。上述缓冲区的长度为65508字节,是我们可以在单个UDP数据包中发送的最大数据量。

给DatagramPacket构造函数的长度是要发送的缓冲区中数据的长度。在该数量的数据之后,缓冲区中的所有数据都将被忽略。

InetAddress实例包含要将UDP数据包发送到的节点(例如服务器)的地址。 " InetAddress"类代表IP地址(Internet地址)。 getByName()方法返回一个InetAddress实例,该实例的IP地址与给定的主机名匹配。

port参数是服务器要接收其列出数据的UDP端口。 UDP和TCP端口不相同。一台计算机可以有不同的进程进行监听,例如同时在UDP和TCP中使用端口80。

要发送" DatagramPacket",我们必须创建一个旨在发送数据的" DatagramSocket"。这是完成的方式:

DatagramSocket datagramSocket = new DatagramSocket();

要发送数据,请调用send()方法,如下所示:

datagramSocket.send(packet);

这是一个完整的示例:

DatagramSocket datagramSocket = new DatagramSocket();

byte[] buffer = "0123456789".getBytes();
InetAddress receiverAddress = InetAddress.getLocalHost();

DatagramPacket packet = new DatagramPacket(
        buffer, buffer.length, receiverAddress, 80);
datagramSocket.send(packet);

通过DatagramSocket接收数据

通过" DatagramSocket"接收数据的方法是先创建一个" DatagramPacket",然后通过" DatagramSocket"的" receive()"方法将数据接收到其中。这是一个例子:

DatagramSocket datagramSocket = new DatagramSocket(80);

byte[] buffer = new byte[10];
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);

datagramSocket.receive(packet);

注意,如何使用传递给其构造函数的参数值80来实例化" DatagramSocket"。这个参数是UDP端口,DatagramSocket用来接收UDP数据包。如前所述,TCP和UDP端口不相同,因此不会重叠。我们可以有两个不同的进程在TCP和UDP端口80上侦听,而不会发生任何冲突。

其次,创建一个字节缓冲区和一个" DatagramPacket"。请注意," DatagramPacket"如何不具有有关要向其发送数据的节点的信息,就像创建" DatagramPacket"来发送数据时一样。这是因为我们将使用DatagramPacket来接收数据,而不是发送数据。因此,不需要目的地地址。

最后,调用DatagramSocket的receive()方法。该方法将阻塞,直到接收到" DatagramPacket"。

接收到的数据位于" DatagramPacket"的字节缓冲区中。可以通过调用以下方法获得此缓冲区:

byte[] buffer = packet.getData();

我们需要确定缓冲区中接收了多少数据。我们使用的协议应指定每个UDP数据包发送多少数据,或者指定我们可以查找的数据结束标记。

真正的服务器程序可能会在循环中调用receive()方法,并将所有接收到的DatagramPacket传递给工作线程池,就像TCP服务器处理传入连接一样。