首页 > 解决方案 > Java NIO 选择器 OP_READ 未触发

问题描述

现在为我工作

首先我创建这样的服务器:

Selector readSelector = Selector.open();
Selector acceptSelector = Selector.open();

ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.socket().bind(new InetSocketAddress(8088));
serverSocketChannel.configureBlocking(false);
serverSocketChannel.register(acceptSelector, SelectionKey.OP_ACCEPT);

然后,在线程中运行它:

while (acceptSelector.isOpen()) {
    acceptSelector.select();
    Iterator<SelectionKey> iterator = acceptSelector.selectedKeys().iterator();
    while (iterator.hasNext()) {
        SelectionKey next = iterator.next();
        iterator.remove();
        if (next.isAcceptable()) {
            SocketChannel socketChannel = serverSocketChannel.accept();
            socketChannel.configureBlocking(false);
            socketChannel.register(readSelector, SelectionKey.OP_READ);
            System.out.println("SOCKET ACCEPT " + socketChannel.getRemoteAddress());
            // There is working find, I can get console output
        }
    }
}

接下来,我尝试读取数据的下一部分:

readSelector.select();
System.out.println("READ SELECTOR"); // This never get triggered
Iterator<SelectionKey> iterator = acceptSelector.selectedKeys().iterator();
while (iterator.hasNext()) {
    SelectionKey next = iterator.next();
    iterator.remove();
    if (next.isReadable()) {
        SocketChannel channel = (SocketChannel) next.channel();
        ByteBuffer byteBuffer = ByteBuffer.allocateDirect(16);
        channel.read(byteBuffer);
        System.out.println("SOCKET READ " + byteBuffer);
    }
}

为什么不触发readSelector.select()

客户端代码(为了方便测试,我没有在客户端使用 nio):

SocketChannel socketChannel = SocketChannel.open();
socketChannel.connect(new InetSocketAddress("127.0.0.1", 8088));

Thread.sleep(1000L);

OutputStream outputStream = socketChannel.socket().getOutputStream();
DataOutputStream dataOutputStream = new DataOutputStream(outputStream);
dataOutputStream.writeUTF("This is DATA");
dataOutputStream.flush();

InputStream inputStream = socketChannel.socket().getInputStream();
DataInputStream dataInputStream = new DataInputStream(inputStream);
String readUTF = dataInputStream.readUTF();
System.out.println(readUTF);

顺便说一句:我见过一些这样的重用代码

Selector selector = Selector.open();
... ...
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
... ...
socketChannel.register(selector, SelectionKey.OP_READ);

ServerSocketChannelSocketChannel使用相同的选择器,这将在我的演示中创建 NPE(接受返回 null),并且我使用if isAcceptable else if isReadable确保我选择了正确的键。

Q1:为什么不触发 OP_READ?
Q2:为什么重用选择器会产生null?

标签: javanio

解决方案


推荐阅读