SelectionKey不可写

时间:2018-03-26 13:08:46

标签: java nio

我很好奇为什么代码总是告诉我“密钥不可写”?我的代码有什么用的吗?每次套接字读取内容时,我都会将密钥设置为对OP_WRITE感兴趣,并测试它是否可写。但是,它总是说不可写。我完全是Java套接字编程的新手。

顺便说一句,我不关闭客户。

public final class DateServer {

    private DateServer() {
    throw new IllegalStateException("Instantiation not allowed");
    }

    public static void main(final String[] args) throws Exception {
        try (final Selector selector = Selector.open(); ServerSocketChannel serverSocket = ServerSocketChannel.open();) {
            InetSocketAddress hostAddress = new InetSocketAddress("127.0.0.1", 9999);
            serverSocket.bind(hostAddress);

            serverSocket.configureBlocking(false);
            serverSocket.register(selector, serverSocket.validOps(), null);

            while (true) {
                int numSelectedKeys = selector.select();
                if (numSelectedKeys > 0) {
                    handleSelectionKeys(selector.selectedKeys(), serverSocket);
                }
            }
        }
    }

    private static void handleSelectionKeys(Set<SelectionKey> selectionKeys, ServerSocketChannel serverSocket) throws IOException {

    Iterator<SelectionKey> selectionKeyIterator = selectionKeys.iterator();
    while (selectionKeyIterator.hasNext()) {
        SelectionKey key = selectionKeyIterator.next();

        if (key.isAcceptable()) {
            acceptClientSocket(key, serverSocket);
        } else if (key.isReadable()) {
            readRequest(key);
        }

        selectionKeyIterator.remove();
    }
    }

    private static void acceptClientSocket(SelectionKey key, ServerSocketChannel serverSocket) throws IOException {

        SocketChannel client = serverSocket.accept();
        client.configureBlocking(false);
        client.register(key.selector(), SelectionKey.OP_READ);

        System.out.println("Accepted connection from client");
    }

    private static void readRequest(SelectionKey key) throws IOException {

        SocketChannel client = (SocketChannel) key.channel();
        ByteBuffer buffer = ByteBuffer.allocate(1024);

        int bytesRead = client.read(buffer);

        if (bytesRead == -1) {
            client.close();
        } else {
            System.out.println(String.format("Request data: %s", new String(buffer.array())));
            int interestOps = 0;
            interestOps |= SelectionKey.OP_WRITE;
            key.interestOps(interestOps);

            if (key.isWritable()){
                System.out.println("key is writable");
            } else {
                System.out.println("key is not writable");
            }

            interestOps = 0;
            interestOps |= SelectionKey.OP_READ;
            key.interestOps(interestOps);
        }

    }
}

2 个答案:

答案 0 :(得分:1)

interestOps只告诉选择器下次为选择什么。设置OP_WRITE并不会神奇地为选择键配备预测未来的能力。您必须再次调用select()以使OP_WRITE实际设置为此代码的结果。

但是您不需要选择器的“权限”来写入频道。你只需写,只有当写入数为零时,你需要担心OP_WRITE,就像这个主题的众多答案一样。

答案 1 :(得分:0)

当您注册客户端时,您只需指定SelectionKey.OP_READ,因此通道永远无法写入。 (查看Selectionkey.java中的isWritable方法)

public final boolean isWritable() {
    return (readyOps() & OP_WRITE) != 0;
}

在您的情况下,OP_WRITE从未注册,因此无效。

使用此功能使其正常工作

client.register(key.selector(), SelectionKey.OP_READ | SelectionKey.OP_WRITE);