Java NIO DatagramChannel
- java
- Nio
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
類提供的open
, bind
, send
和receive
之類的方法**。現在,讓我們快速瀏覽一下其他方便的方法。
7.1 configureBlocking
默認情況下,數據報通道處於阻塞狀態。 false
值時,我們可以使用configureBlocking
方法使通道變為非阻塞狀態:
client.configureBlocking(false);
7.2 isConnected
isConnected
方法返回數據報通道的狀態-即它是已連接還是已斷開連接。
7.3 socket
socket
方法返回與數據報通道關聯DatagramSocket
7.4。close
另外,我們可以通過調用DatagramChannel
類close
方法來關閉通道。
8.結論
在本快速教程中,我們探討了Java NIO的DatagramChannel
類,該類允許創建一個數據報通道來發送/接收UDP數據包。
首先,我們研究了一些方法,例如open
和bind
,它們同時允許數據報通道偵聽入站UDP數據包。
然後,我們創建了一個客戶端和一個服務器, DatagramChannel
類探索端到端UDP數據包的傳遞。