Java併發編程學習-日記2、NIO實現Discard服務器實踐

 

  • 源碼分析:

  1. ServerSocketChannel是一個可以監聽新進來的TCP連接的通道,就像標準IO中的ServerSocket一樣。
  2. 通過ServerSocketChannel.accept()方法監聽新進來的連接。當accept()方法返回的時候,它返回一個包含新進來的連接的SocketChannel。
  3. 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();
    }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章