Java NIO DatagramChannel

1.概述

在本教程中,我們將探索DatagramChannel類,該類允許我們發送和接收UDP數據包。

2. DatagramChannel

在Internet支持的各種協議中,TCP和UDP是最常見的。

TCP是面向連接的協議,而UDP是高性能且可靠性較低的面向數據報的協議UDP由於其不可靠的特性而經常用於發送廣播或多播數據傳輸。

Java的NIO模塊的DatagramChannel類為面向數據報的套接字提供了一個可選通道。換句話說,它允許創建一個數據報通道來發送和接收數據報(UDP數據包)。

讓我們使用DatagramChannel類創建一個客戶端,該客戶端通過本地IP地址發送數據報,並創建一個接收數據報的服務器。

3.打開並綁定

首先,讓我們openChannel DatagramChannelBuilder類,該方法提供一個打開但未連接的數據報通道:

public class DatagramChannelBuilder {

 public static DatagramChannel openChannel() throws IOException {

 DatagramChannel datagramChannel = DatagramChannel.open();

 return datagramChannel;

 }

 }

然後,我們需要將一個打開的通道綁定到本地地址,以偵聽入站UDP數據包。

因此,我們將添加bindChannel方法, DatagramChannel綁定到提供的本地地址:

public static DatagramChannel bindChannel(SocketAddress local) throws IOException {

 return openChannel().bind(local);

 }

現在,我們可以使用DatagramChannelBuilder類來創建客戶端/服務器,該客戶端/服務器在已配置的套接字地址上發送/接收UDP數據包。

4.客戶端

首先,讓我們創建DatagramClient與類startClient使用已經討論過的方法bindChannel的方法DatagramChannelBuilder類:

public class DatagramClient {

 public static DatagramChannel startClient() throws IOException {

 DatagramChannel client = DatagramChannelBuilder.bindChannel(null);

 return client;

 }

 }

由於客戶端不需要偵聽入站UDP數據包,因此在綁定通道時我們為地址null

然後,我們添加sendMessage方法以在服務器地址上發送數據報:

public static void sendMessage(DatagramChannel client, String msg, SocketAddress serverAddress) throws IOException {

 ByteBuffer buffer = ByteBuffer.wrap(msg.getBytes());

 client.send(buffer, serverAddress);

 }

就是這樣!現在,我們準備使用客戶端發送消息:

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);

注意:將消息發送到localhost:7001地址後,必須使用相同的地址啟動服務器。

5.服務器

同樣,讓我們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;

 }

 }

然後,讓我們添加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);

 }

另外,要從接收的緩衝區中提取客戶端的消息,我們將需要添加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;

 }

在這裡,我們ByteBuffer flip方法,以將其從I / O讀取轉換為寫入I / O。另外, flip方法將限制設置為當前位置,並將位置設置為零,以便我們從頭開始閱讀。

現在,我們可以啟動服務器並接收來自客戶端的消息:

DatagramChannel server = startServer();

 receiveMessage(server);

因此,服務器收到我們的消息時,打印輸出將是:

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

現在我們已經準備好客戶端和服務器,我們可以編寫一個單元測試來驗證端到端數據報(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));

 }

首先,我們啟動了綁定數據報通道的服務器,以偵聽localhost:7001上的入站消息。然後,我們啟動了客戶端並發送了兩條消息。

最後,我們在服務器上收到入站消息,並將它們與我們通過客戶端發送的消息進行比較。

7.附加方法

到目前為止,我們已經使用**DatagramChannel類提供的openbindsendreceive之類的方法**。現在,讓我們快速瀏覽一下其他方便的方法。

7.1 configureBlocking

默認情況下,數據報通道處於阻塞狀態。 false值時,我們可以使用configureBlocking方法使通道變為非阻塞狀態:

client.configureBlocking(false);

7.2 isConnected

isConnected方法返回數據報通道的狀態-即它是已連接還是已斷開連接。

7.3 socket

socket方法返回與數據報通道關聯DatagramSocket

7.4。close

另外,我們可以通過調用DatagramChannelclose方法來關閉通道。

8.結論

在本快速教程中,我們探討了Java NIO的DatagramChannel類,該類允許創建一個數據報通道來發送/接收UDP數據包。

首先,我們研究了一些方法,例如openbind ,它們同時允許數據報通道偵聽入站UDP數據包。

然後,我們創建了一個客戶端和一個服務器, DatagramChannel類探索端到端UDP數據包的傳遞