A Guide To UDP In Java – Java中的UDP指南

最后修改: 2016年 10月 26日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

In this article, we will be exploring networking communication with Java, over the User Datagram Protocol (UDP).

在这篇文章中,我们将通过用户数据报协议(UDP),探讨用Java进行网络通信。

UDP is a communication protocol that transmits independent packets over the network with no guarantee of arrival and no guarantee of the order of delivery.

UDP是一种通信协议,在网络上传送独立的数据包,不保证到达,也不保证传送的顺序

Most communication over the internet takes place over the Transmission Control Protocol (TCP), however, UDP has its place which we will be exploring in the next section.

互联网上的大多数通信都是通过传输控制协议(TCP)进行的,然而,UDP也有它的地位,我们将在下一节进行探讨。

2. Why Use UDP?

2.为什么使用UDP?

UDP is quite different from the more common TCP. But before considering the surface level disadvantages of UDP, it’s important to understand that the lack of overhead can make it significantly faster than TCP.

UDP与更常见的TCP有很大不同。但在考虑UDP的表面缺点之前,重要的是要了解没有开销可以使它的速度明显高于TCP。

Apart from speed, we also need to remember that some kinds of communication do not require the reliability of TCP but value low latency instead. The video is a good example of an application that might benefit from running over UDP instead of TCP.

除了速度之外,我们还需要记住,有些类型的通信不需要TCP的可靠性,而是重视低延迟。该视频是一个很好的例子,说明通过UDP而不是TCP运行的应用程序可能会受益。

3. Building UDP Applications

3.构建UDP应用

Building UDP applications is very similar to building a TCP system; the only difference is that we don’t establish a point to point connection between a client and a server.

构建UDP应用程序与构建TCP系统非常相似;唯一不同的是,我们不在客户端和服务器之间建立点对点的连接。

The setup is very straightforward too. Java ships with built-in networking support for UDP – which is part of the java.net package. Therefore to perform networking operations over UDP, we only need to import the classes from the java.net package: java.net.DatagramSocket and java.net.DatagramPacket.

设置也是非常简单的。Java内置了对UDP的网络支持–它是java.net包的一部分。因此,要在UDP上执行网络操作,我们只需要从java.net包中导入类。java.net.DatagramSocketjava.net.DatagramPacket

In the following sections, we will learn how to design applications that communicate over UDP; we’ll use the popular echo protocol for this application.

在下面的章节中,我们将学习如何设计通过UDP进行通信的应用程序;我们将使用流行的echo协议来实现这一应用。

First, we will build an echo server that sends back any message sent to it, then an echo client that just sends any arbitrary message to the server and finally, we will test the application to ensure everything is working fine.

首先,我们将建立一个回声服务器,将任何发送到它的消息发送回来,然后建立一个回声客户端,只是将任何任意的消息发送到服务器,最后,我们将测试该应用程序,以确保一切工作正常。

4. The Server

4.服务器

In UDP communication, a single message is encapsulated in a DatagramPacket which is sent through a DatagramSocket.

在UDP通信中,单个消息被封装在一个DatagramPacket中,通过一个DatagramSocket发送。

Let’s start by setting up a simple server:

让我们从建立一个简单的服务器开始。

public class EchoServer extends Thread {

    private DatagramSocket socket;
    private boolean running;
    private byte[] buf = new byte[256];

    public EchoServer() {
        socket = new DatagramSocket(4445);
    }

    public void run() {
        running = true;

        while (running) {
            DatagramPacket packet 
              = new DatagramPacket(buf, buf.length);
            socket.receive(packet);
            
            InetAddress address = packet.getAddress();
            int port = packet.getPort();
            packet = new DatagramPacket(buf, buf.length, address, port);
            String received 
              = new String(packet.getData(), 0, packet.getLength());
            
            if (received.equals("end")) {
                running = false;
                continue;
            }
            socket.send(packet);
        }
        socket.close();
    }
}

We create a global DatagramSocket which we will use throughout to send packets, a byte array to wrap our messages, and a status variable called running.

我们创建了一个全局的DatagramSocket,我们将自始至终使用它来发送数据包,一个字节数组来包装我们的消息,以及一个名为running的状态变量。

For simplicity, the server is extending Thread, so we can implement everything inside the run method.

为了简单起见,服务器扩展了Thread,所以我们可以在run方法中实现一切。

Inside run, we create a while loop that just runs until running is changed to false by some error or a termination message from the client.

run内,我们创建了一个while循环,它一直运行到running被一些错误或来自客户端的终止消息改变为false为止。

At the top of the loop, we instantiate a DatagramPacket to receive incoming messages.

在循环的顶部,我们实例化一个DatagramPacket来接收传入的消息。

Next, we call the receive method on the socket. This method blocks until a message arrives and it stores the message inside the byte array of the DatagramPacket passed to it.

接下来,我们在套接字上调用receive方法。这个方法会阻塞,直到有消息到达,并将消息存储在传递给它的DatagramPacket的字节数里。

After receiving the message, we retrieve the address and port of the client, since we are going to send the response
back.

在收到消息后,我们检索客户端的地址和端口,因为我们要发送响应

返回。

Next, we create a DatagramPacket for sending a message to the client. Notice the difference in signature with the receiving packet. This one also requires address and port of the client we are sending the message to.

接下来,我们创建一个DatagramPacket,用于向客户端发送一个消息。注意与接收数据包的签名不同。这个包也需要我们发送消息的客户端的地址和端口。

5. The Client

5.客户

Now let’s roll out a simple client for this new server:

现在让我们为这个新服务器推出一个简单的客户端。

public class EchoClient {
    private DatagramSocket socket;
    private InetAddress address;

    private byte[] buf;

    public EchoClient() {
        socket = new DatagramSocket();
        address = InetAddress.getByName("localhost");
    }

    public String sendEcho(String msg) {
        buf = msg.getBytes();
        DatagramPacket packet 
          = new DatagramPacket(buf, buf.length, address, 4445);
        socket.send(packet);
        packet = new DatagramPacket(buf, buf.length);
        socket.receive(packet);
        String received = new String(
          packet.getData(), 0, packet.getLength());
        return received;
    }

    public void close() {
        socket.close();
    }
}

The code is not that different from the server’s. We have our global DatagramSocket and address of the server. We instantiate these inside the constructor.

这些代码与服务器的代码没有什么不同。我们有我们的全局DatagramSocket和服务器的地址。我们在构造函数中对这些进行实例化。

We have a separate method which sends messages to the server and returns the response.

我们有一个单独的方法,向服务器发送消息并返回响应。

We first convert the string message into a byte array, then create a DatagramPacket for sending messages.

我们首先将字符串消息转换为字节数组,然后创建一个DatagramPacket用于发送消息。

Next – we send the message. We immediately convert the DatagramPacket into a receiving one.

接下来–我们发送消息。我们立即将DatagramPacket转换成一个接收的。

When the echo arrives, we convert the bytes to a string and return the string.

当回声到达时,我们将字节转换为字符串并返回该字符串。

6. The Test

6.测试

In a class UDPTest.java, we simply create one test to check the echoing ability of our two applications:

在一个UDPTest.java类中,我们简单地创建一个测试来检查我们两个应用程序的回声能力。

public class UDPTest {
    EchoClient client;

    @Before
    public void setup(){
        new EchoServer().start();
        client = new EchoClient();
    }

    @Test
    public void whenCanSendAndReceivePacket_thenCorrect() {
        String echo = client.sendEcho("hello server");
        assertEquals("hello server", echo);
        echo = client.sendEcho("server is working");
        assertFalse(echo.equals("hello server"));
    }

    @After
    public void tearDown() {
        client.sendEcho("end");
        client.close();
    }
}

In setup, we start the server and also create the client. While in the tearDown method, we send a termination message to the server so that it can close and at the same time we close the client.

setup中,我们启动服务器并创建客户端。而在tearDown方法中,我们向服务器发送一个终止消息,以便它能够关闭,同时我们也关闭客户端。

7. Conclusion

7.结论

In this article, we have learned about the User Datagram Protocol and successfully built our own client-server applications that communicate over UDP.

在这篇文章中,我们已经了解了用户数据报协议,并成功地建立了自己的客户-服务器应用程序,通过UDP进行通信。

To get full source code for the examples used in this article, you can check out the GitHub project.

要获得本文中使用的例子的完整源代码,你可以查看GitHub项目