1. Overview
1.概述
In this tutorial, we’ll explore the DatagramChannel class that allows us to send and receive UDP packets.
在本教程中,我们将探讨DatagramChannel类,它允许我们发送和接收UDP数据包。
2. DatagramChannel
2.DatagramChannel
Among various protocols supported on the internet, TCP and UDP are the most common.
在互联网上支持的各种协议中,TCP和UDP是最常见的。
While TCP is a connection-oriented protocol, UDP is a datagram-oriented protocol that is highly performant and less reliable. UDP is often used in sending broadcast or multicast data transmissions due to its unreliable nature.
TCP是一个面向连接的协议,而UDP是一个面向数据报的协议,性能高,可靠性差。UDP由于其不可靠的特性,经常被用于发送广播或多播数据传输。
The DatagramChannel class of Java’s NIO module provides a selectable channel for the datagram-oriented sockets. In other words, it allows creating a datagram channel to send and receive the datagrams (UDP packets).
DatagramChannel类的Java的NIO模块提供面向数据包的可选择通道。换句话说,它允许创建一个数据报通道来发送和接收数据包(UDP数据包)。
Let’s use the DatagramChannel class to create a client that sends the datagrams over the local IP address and a server that receives the datagram.
让我们使用DatagramChannel类来创建一个通过本地IP地址发送数据报的客户端和一个接收数据报的服务器。
3. Open and Bind
3.打开并绑定
First, let’s create the DatagramChannelBuilder class with the openChannel method that provides an opened but unconnected datagram channel:
首先,让我们创建带有openChannel方法的DatagramChannelBuilder类,该方法提供一个已打开但未连接的数据报通道。
public class DatagramChannelBuilder {
public static DatagramChannel openChannel() throws IOException {
DatagramChannel datagramChannel = DatagramChannel.open();
return datagramChannel;
}
}
Then, we’ll require to bind an opened channel to the local address for listening to the inbound UDP packets.
然后,我们需要在本地地址上绑定一个开放的通道,用于监听入站的UDP数据包。
So, we’ll add the bindChannel method that binds the DatagramChannel to the provided local address:
因此,我们将添加bindChannel方法,将DatagramChannel与提供的本地地址绑定。
public static DatagramChannel bindChannel(SocketAddress local) throws IOException {
return openChannel().bind(local);
}
Now, we can use the DatagramChannelBuilder class to create the client/server that sends/receives the UDP packets on the configured socket address.
现在,我们可以使用DatagramChannelBuilder类来创建客户端/服务器,在配置的套接字地址上发送/接收UDP包。
4. Client
4.客户
First, let’s create the DatagramClient class with the startClient method that uses the already discussed bindChannel method of the DatagramChannelBuilder class:
首先,让我们创建DatagramClient类,其startClient方法使用已经讨论过的DatagramChannelBuilder类的bindChannel方法。
public class DatagramClient {
public static DatagramChannel startClient() throws IOException {
DatagramChannel client = DatagramChannelBuilder.bindChannel(null);
return client;
}
}
As the client doesn’t require listening to the inbound UDP packets, we’ve provided a null value for the address while binding the channel.
由于客户端不需要监听入站的UDP数据包,我们在绑定通道时为地址提供了一个null值。
Then, let’s add the sendMessage method to send a datagram on the server address:
然后,让我们添加sendMessage方法,在服务器地址上发送一个数据报。
public static void sendMessage(DatagramChannel client, String msg, SocketAddress serverAddress) throws IOException {
ByteBuffer buffer = ByteBuffer.wrap(msg.getBytes());
client.send(buffer, serverAddress);
}
That’s it! Now we’re ready to send our message using the client:
这就是了!现在我们已经准备好使用客户端发送我们的信息了。
DatagramChannel client = startClient();
String msg = "Hello, this is a Baeldung's DatagramChannel based UDP client!";
InetSocketAddress serverAddress = new InetSocketAddress("localhost", 7001);
sendMessage(client, msg, serverAddress);
Note: As we’ve sent our message to the localhost:7001 address, we must start our server using the same address.
注意:由于我们已经将信息发送到localhost:7001地址,我们必须使用相同的地址启动我们的服务器。
5. Server
5.服务器
Similarly, let’s create the DatagramServer class with the startServer method to start a server on the localhost:7001 address:
同样,让我们创建带有startServer方法的DatagramServer类,在localhost:7001地址上启动一个服务器。
public class DatagramServer {
public static DatagramChannel startServer() throws IOException {
InetSocketAddress address = new InetSocketAddress("localhost", 7001);
DatagramChannel server = DatagramChannelBuilder.bindChannel(address);
System.out.println("Server started at #" + address);
return server;
}
}
Then, let’s add the receiveMessage method that receives the datagrams from the client, extracts the message, and prints it:
然后,让我们添加receiveMessage方法,从客户端接收数据报,提取消息,并打印出来。
public static void receiveMessage(DatagramChannel server) throws IOException {
ByteBuffer buffer = ByteBuffer.allocate(1024);
SocketAddress remoteAdd = server.receive(buffer);
String message = extractMessage(buffer);
System.out.println("Client at #" + remoteAdd + " sent: " + message);
}
Also, to extract the client’s message from the received buffer, we’ll require to add the extractMessage method:
另外,为了从收到的缓冲区中提取客户端的信息,我们需要添加extractMessage方法。
private static String extractMessage(ByteBuffer buffer) {
buffer.flip();
byte[] bytes = new byte[buffer.remaining()];
buffer.get(bytes);
String msg = new String(bytes);
return msg;
}
Here, we’ve used the flip method on the ByteBuffer instance to flip it from reading from I/O to writing to I/O. Additionally, the flip method sets the limit to the current position and the position to zero to let us read from the beginning.
在这里,我们在ByteBuffer实例上使用了flip方法,将其从I/O读取翻转到I/O写入。此外,flip方法将极限值设置为当前位置,将位置设置为零,以便让我们从头开始读取。
Now, we can start our server and receive a message from the client:
现在,我们可以启动我们的服务器并接收来自客户端的信息。
DatagramChannel server = startServer();
receiveMessage(server);
Therefore, the print output when the server receives our message will be:
因此,当服务器收到我们的信息时,打印输出将是。
Server started at #localhost/127.0.0.1:7001
Client at #/127.0.0.1:52580 sent: Hello, this is a Baeldung's DatagramChannel based UDP client!
6. DatagramChannelUnitTest
6.DatagramChannelUnitTest
Now that we have both client and server ready, we can write a unit test to verify the end-to-end datagram (UDP packet) delivery:
现在我们已经准备好了客户端和服务器,我们可以写一个单元测试来验证端到端的数据报(UDP包)交付。
@Test
public void whenClientSendsAndServerReceivesUDPPacket_thenCorrect() throws IOException {
DatagramChannel server = DatagramServer.startServer();
DatagramChannel client = DatagramClient.startClient();
String msg1 = "Hello, this is a Baeldung's DatagramChannel based UDP client!";
String msg2 = "Hi again!, Are you there!";
InetSocketAddress serverAddress = new InetSocketAddress("localhost", 7001);
DatagramClient.sendMessage(client, msg1, serverAddress);
DatagramClient.sendMessage(client, msg2, serverAddress);
assertEquals("Hello, this is a Baeldung's DatagramChannel based UDP client!", DatagramServer.receiveMessage(server));
assertEquals("Hi again!, Are you there!", DatagramServer.receiveMessage(server));
}
First, we’ve started the server that binds the datagram channel to listen to the inbound message on localhost:7001. Then, we started the client and sent two messages.
首先,我们已经启动了绑定数据报通道的服务器,在localhost:7001上监听入站消息。然后,我们启动了客户端并发送了两条消息。
Last, we received the inbound messages on the server and compared them with the messages we sent through the client.
最后,我们在服务器上接收入站信息,并将其与我们通过客户端发送的信息进行比较。
7. Additional Methods
7.其他方法
So far, we’ve used methods like open, bind, send, and receive provided by the DatagramChannel class. Now, let’s quickly go through its other handy methods.
到目前为止,我们已经使用了DatagramChannel类提供的open、bind、send、receive等方法。现在,让我们快速浏览一下它的其他方便的方法。
7.1. configureBlocking
7.1.configureBlocking
By default, the datagram channel is blocking. We can use the configureBlocking method to make the channel non-blocking when passing the false value:
默认情况下,数据报通道是阻塞的。我们可以使用configureBlocking方法,在传递false值时,使通道不阻塞。
client.configureBlocking(false);
7.2. isConnected
7.2.isConnected
The isConnected method returns the status of the datagram channel — that is, whether it’s connected or disconnected.
isConnected方法返回数据报通道的状态,也就是说,它是连接还是断开。
7.3. socket
7.3. 插座
The socket method returns the object of the DatagramSocket class associated with the datagram channel.
socket方法返回与数据报通道相关的DatagramSocket类的对象。
7.4. close
7.4.关闭
Additionally, we can close the channel by calling the close method of the DatagramChannel class.
此外,我们可以通过调用DatagramChannel类的close方法关闭该通道。
8. Conclusion
8.结语
In this quick tutorial, we explored Java NIO’s DatagramChannel class that allows the creation of a datagram channel to send/receive UDP packets.
在这个快速教程中,我们探讨了Java NIO的DatagramChannel类,它允许创建一个数据报通道来发送/接收UDP包。
First, we examined a few methods like open and bind that simultaneously allow the datagram channel to listen to the inbound UDP packets.
首先,我们研究了一些方法,如open和bind,同时允许数据报通道监听入站的UDP数据包。
Then, we created a client and a server to explore the end-to-end UDP packet delivery using the DatagramChannel class.
然后,我们创建了一个客户端和一个服务器来探索使用DatagramChannel类的端到端UDP数据包传输。
As usual, the source code is available over on GitHub.
像往常一样,源代码可在GitHub上获得。