下面以一個執行個體介紹 NonBlockingNIO 的用法
/**
* 一、使用 NIO 完成網絡通信的三個核心:
*
* 1. 通道(Channel):負責連接配接
*
* java.nio.channels.Channel 接口:
* |--SelectableChannel
* |--SocketChannel
* |--ServerSocketChannel
* |--DatagramChannel
*
* |--Pipe.SinkChannel
* |--Pipe.SourceChannel
*
* 2. 緩沖區(Buffer):負責資料的存取
*
* 3. 選擇器(Selector):是 SelectableChannel 的多路複用器。用于監控 SelectableChannel 的 IO 狀況
*
*/
public class TestNonBlockingNIO {
// 用戶端
public static void main(String[] args) throws IOException {
// 1、擷取通道
SocketChannel sChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 8989));
// 2、切換為非阻塞模式
sChannel.configureBlocking(false);
// 3、配置設定緩沖區
ByteBuffer buffer = ByteBuffer.allocate(1024);
// 4、發送資料給服務端
Scanner scanner = new Scanner(System.in);
while (scanner.hasNext()) {
String next = scanner.next();
buffer.put((new Date() + "\n" + next).getBytes());
buffer.flip();
sChannel.write(buffer);
buffer.clear();
}
// 5、關閉通道
scanner.close();
}
// 服務端
@Test
public void server() throws IOException {
// 1、擷取通道
ServerSocketChannel ssChannel = ServerSocketChannel.open();
// 2、切換非阻塞模式
ssChannel.configureBlocking(false);
// 3、綁定連接配接
ssChannel.bind(new InetSocketAddress(8989));
// 4、擷取選擇器
Selector selector = Selector.open();
// 5、将通道注冊到選擇器上,并指定"監聽接收事件"
ssChannel.register(selector, SelectionKey.OP_ACCEPT);
// 6、輪詢式的擷取選擇器上已經"準備就緒"的事件
while (selector.select() > 0) {
// 7、擷取目前選擇器中所有已就緒的監聽事件
Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
while (iterator.hasNext()) {
// 8、擷取準備就緒的事件
SelectionKey key = iterator.next();
// 9、判斷具體是什麼事件準備就緒
if (key.isAcceptable()) {
// 如果就緒事件為"接收就緒",則擷取用戶端連接配接
SocketChannel sChannel = ssChannel.accept();
// 設定為非阻塞模式
sChannel.configureBlocking(false);
// 同時把通道注冊到選擇器上
sChannel.register(selector, SelectionKey.OP_READ);
} else if (key.isReadable()) {
// 擷取目前選擇器上“讀就緒”狀态的通道
SocketChannel sChannel = (SocketChannel) key.channel();
// 讀取用戶端資料
ByteBuffer buffer = ByteBuffer.allocate(1024);
int len = 0;
while ((len = sChannel.read(buffer)) > 0) {
buffer.flip();
System.out.println(">>> " + new String(buffer.array(), 0, len));
buffer.clear();
}
}
// 10、移除已經使用的選擇鍵
iterator.remove();
}
}
}
}
下面的執行個體為資料報版本
/**
* 測試資料報的非阻塞通道
*/
public class TestNonBlockingNIO2 {
// 發送端
public static void main(String[] args) throws IOException {
DatagramChannel sendChannel = DatagramChannel.open();
sendChannel.configureBlocking(false);
Scanner scanner = new Scanner(System.in);
ByteBuffer buffer = ByteBuffer.allocate(1024);
InetSocketAddress socketAddress = new InetSocketAddress("127.0.0.1", 8899);
while (scanner.hasNext()) {
String data = scanner.next();
buffer.put((new Date() + "\n" + data).getBytes());
buffer.flip();
sendChannel.send(buffer, socketAddress);
buffer.clear();
}
sendChannel.close();
}
// 接收端
@Test
public void receiver() throws IOException{
DatagramChannel recvChannel = DatagramChannel.open();
recvChannel.configureBlocking(false);
recvChannel.bind(new InetSocketAddress(8899));
Selector selector = Selector.open();
recvChannel.register(selector, SelectionKey.OP_READ);
while (selector.select() > 0) {
Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
while (iterator.hasNext()) {
SelectionKey key = iterator.next();
if (key.isReadable()) {
ByteBuffer buffer = ByteBuffer.allocate(1024);
recvChannel.receive(buffer);
buffer.flip();
System.out.println(">>> " + new String(buffer.array(), 0, buffer.limit()));
buffer.clear();
}
}
iterator.remove();
}
}
}