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

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