-
源碼分析:
- ServerSocketChannel是一個可以監聽新進來的TCP連接的通道,就像標準IO中的ServerSocket一樣。
- 通過ServerSocketChannel.accept()方法監聽新進來的連接。當accept()方法返回的時候,它返回一個包含新進來的連接的SocketChannel。
- ServerSocketChannel可以設置成非阻塞模式:serverSocketChannel.configureBlocking(false); 在非阻塞模式下,accept()方法會立刻返回,如果還沒有新進來的連接,返回的將是null。
-
服務端和客戶端源碼:
public class NioDiscardServer {
public static void startServer() throws IOException {
Selector selector = Selector.open();// 1、獲取Selector選擇器
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();// 2、獲取通道
serverSocketChannel.configureBlocking(false); // 3.設置爲非阻塞
serverSocketChannel.bind(new InetSocketAddress(9000));// 4、綁定連接
// 5、將通道註冊到選擇器上,並註冊的IO事件爲:“接收新連接”
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
// 6、輪詢感興趣的I/O就緒事件(選擇鍵集合)
while (selector.select() > 0) {
// 7、獲取選擇鍵集合
Iterator<SelectionKey> selectedKeys = selector.selectedKeys().iterator();
while (selectedKeys.hasNext()) {
SelectionKey selectedKey = selectedKeys.next();// 8、獲取單個的選擇鍵,並處理
// 9、判斷key是具體的什麼事件,不同的事件類型,做不同的處理
if (selectedKey.isAcceptable()) {
// 10-1、若選擇鍵的IO事件是“連接就緒”事件,就獲取客戶端連接,此時新的客戶端請求連接,需要獲取鏈接通道,並將通道綁定到選擇器上。
SocketChannel socketChannel = serverSocketChannel.accept();
socketChannel.configureBlocking(false); // 10-1、切換爲非阻塞模式
socketChannel.register(selector, SelectionKey.OP_READ); // 10-1、將該通道註冊到selector選擇器上
} else if (selectedKey.isReadable()) {
// 10-2、若選擇鍵的IO事件是“可讀”事件,讀取數據
SocketChannel socketChannel = (SocketChannel) selectedKey.channel();
// 10-2、讀取數據
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
int length = 0;
while ((length = socketChannel.read(byteBuffer)) >0) {
byteBuffer.flip();
Logger.info(new String(byteBuffer.array(), 0, length));
byteBuffer.clear();
}
socketChannel.close();
}
// 15、移除選擇鍵
selectedKeys.remove();
}
}
// 7、關閉連接
serverSocketChannel.close();
}
public static void main(String[] args) throws IOException {
startServer();
}
}
public class NioDiscardClient {
public static void startClient() throws IOException {
SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress(127.0.01,9000));// 1、獲取通道(channel)
socketChannel.configureBlocking(false); // 2、切換成非阻塞模式
while (!socketChannel.finishConnect()) { //3.不斷的自旋、等待連接完成,或者做一些其他的事情
}
ByteBuffer byteBuffer = ByteBuffer.allocate(1024); // 4、分配指定大小的緩衝區
byteBuffer.put("hello world".getBytes());
byteBuffer.flip();
socketChannel.write(byteBuffer);
socketChannel.shutdownOutput();
socketChannel.close();
}
public static void main(String[] args) throws IOException {
startClient();
}
}