NIO的读就绪一直触发

新手上路,请多包涵

在selector注册了读就绪监听之后,读就绪事件就一直触发。
NIO的读就绪触发条件应该是内核缓存区有数据才触发,现在是哪怕客户端不发送消息,读就绪事件也会触发。

public class Server {
    public static void main(String[] args) throws Exception {
 
        SocketAddress socketAddress = new InetSocketAddress("127.0.0.1", 8080);
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        serverSocketChannel.bind(socketAddress);
 
        serverSocketChannel.configureBlocking(false);
        Selector selector = Selector.open();
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
 
        while (true) {
            selector.select();
            Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
            while (iterator.hasNext()) {
                SelectionKey selectionKey = iterator.next();
                // accept就绪
                if (selectionKey.isAcceptable()) {
                    ServerSocketChannel serverSocket = (ServerSocketChannel) selectionKey.channel();
                    SocketChannel socketChannel = serverSocket.accept();
                    socketChannel.configureBlocking(false);
                    socketChannel.register(selector, SelectionKey.OP_READ);
                }
                // 读就绪
                if (selectionKey.isReadable()) {
                    SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
                    ByteBuffer buffer = ByteBuffer.allocate(1024);
                    int len = 0;
                    while ((len = socketChannel.read(buffer))!=-1) {
                        buffer.flip();
                        System.out.println(new String(buffer.array(),0,len));
                        buffer.clear();
                    }
                    System.out.println("读就绪");
                }
                 
                iterator.remove();
            }
        }
    }
}

客户端代码

public class Client {
    public static void main(String[] args) throws Exception{
        SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1",8080));
 
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        buffer.put("你好,我来了".getBytes());
        buffer.flip();
        socketChannel.write(buffer);
        socketChannel.shutdownOutput();
 
        socketChannel.close();
    }
}
阅读 3.2k
1 个回答

(stackoverflow原话)If bytesRead < 0 you should close the channel or at least deregister OP_READ. Otherwise you will keep getting OP_READ over and over again to tell you about the EOS.

原因就在于断开连接后,为了让你知道连接已断开,所以会产生OP_READ事件。

当客户端的链接异常断开,此时代表这个链接的channel一直处于readable的状态,如何检查链接已断开呢?链接断开后,虽然该channel的ready operation是OP_READ,但是此时channel.read(buffer)返回-1,此时可以增加一个判断。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题