NIO selector多路复用器

十年热恋 提交于 2020-04-27 02:21:34
  1. 基本流程与C语言一样:
    • socket 设置非阻塞、bind绑定端口、listen监听连接、epoll_create、添加socket到epoll监听EPOLLIN、epoll_wait等待连接事件就绪的连接
      • accpet新连接。得到socket且设置非阻塞、添加到epoll监听EPOLLIN
      • 新的socket EPOLLIN事件就绪。读取数据。
        • 如果程度是-1说明客户端关闭连接。JAVA中需要调用 channel.cancel()
        • 否则是正常数据输入
      • selectionKey.remove()
public void testScannerServer() throws IOException {
    System.out.println("服务端开启");
    ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();

    // 非阻塞
    serverSocketChannel.configureBlocking(false);

    serverSocketChannel.bind(new InetSocketAddress(8092));

    Selector selector = Selector.open();

    serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

    while (selector.select() > 0) {

		// it won't clear the existing items 不会清空已经存在的 selectionKey。因此遍历处理一个后需要remove移除
        Iterator<SelectionKey> it = selector.selectedKeys().iterator();

        while (it.hasNext()) {
            SelectionKey key = it.next();
            // 为什么要remove?因为 select 就绪队列,如果不移除就会一直存在
            // https://stackoverflow.com/questions/7132057/why-the-key-should-be-removed-in-selector-selectedkeys-iterator-in-java-ni
            it.remove();
            if (!key.isValid()) {
                System.out.println("连接不可用");
            } else if (key.isAcceptable()) {
                // 新连接
                System.out.println("服务端接受到新连接");
                SocketChannel socketChannel = serverSocketChannel.accept();
                socketChannel.configureBlocking(false); // 非阻塞
                socketChannel.register(selector, SelectionKey.OP_READ); // 注册可读事件
            } else if (key.isReadable()) {
                // 有客户端发送数据
                SocketChannel socketChannel = (SocketChannel) key.channel();
                // 开始读取数据
                System.out.println(new Date().toString());
                ByteBuffer byteBuffer = ByteBuffer.allocate(1024);

                if (socketChannel.read(byteBuffer) == -1) {
                    // -1 说明客户端关闭了写或者直接close
                    System.out.println("客户端关闭连接");
                    // socketChannel.close(); // 其实不需要调用,因为客户端已经关闭, 为了程序稳健性可以开启
                    key.cancel(); // 取消注册
                } else {
                    byteBuffer.flip();
                    System.out.println(new String(byteBuffer.array(), 0, byteBuffer.limit()));
                    byteBuffer.clear();
                }
            }
        }
    }
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!