SelectionKey.isAcceptable()当没有传入连接时返回“true”

时间:2014-09-18 07:19:59

标签: java sockets nio

我正在使用Java NIO用Java编写聊天服务器。服务器接受连接没有问题,但只要select()返回>在第一个客户端之后,即使没有挂起的连接,服务器套接字也始终位于所选的密钥集中。即使select()返回1,所选的键集也将包含2个元素并包含服务器套接字。这会导致accept()返回null。

非常感谢任何帮助。

主循环:

public void start() throws IOException {
    Set<SelectionKey>       keys;
    Iterator<SelectionKey>  keyIterator;
    this.keepGoing = true;

    while (keepGoing) {
        int readyChannels = this.selector.select();

        if (readyChannels == 0) 
        {
            continue;
        }

        keys        = this.selector.selectedKeys();
        keyIterator = keys.iterator();

        while (keyIterator.hasNext())
        {
            SelectionKey currentKey = keyIterator.next();

            if (currentKey.isAcceptable())
            {
                addClient(currentKey);
            }
            if (currentKey.isReadable())
            {
                readSock(currentKey);
            }
            if (currentKey.isWritable())
            {
                // write data to the buffer and remove OP_WRITE
            }
        }
    }

}

服务器初始化代码:

public Server(int port) {

    this.listenPort = port;

    try
    {
        this.selector = Selector.open();
        this.listenChannel = ServerSocketChannel.open();
        this.listenChannel.socket().bind(new InetSocketAddress(this.listenPort), BACKLOG);
        this.listenChannel.configureBlocking(false);
        this.listenChannel.register(this.selector, SelectionKey.OP_ACCEPT);
    } 
    catch (IOException e)
    {
        System.out.println("Server could not initialise: " + e.getMessage());
    }

    this.users = new HashMap<>();
}

addClient方法:

private void addClient(SelectionKey key) throws IOException {
    ServerSocketChannel acceptSocket    = (ServerSocketChannel) key.channel();
    SocketChannel       newClient       = acceptSocket.accept();
    SelectionKey        clientKey;

    // Set the new client to non-blocking mode and add to the selector
    newClient.configureBlocking(false);
    clientKey = newClient.register(this.selector, SelectionKey.OP_READ);

    // Add a new key-user pair to the user list
    this.users.put(clientKey, new User());

    // Attach a buffer for reading the packets
    clientKey.attach(new PacketBuffer(newClient));
}

1 个答案:

答案 0 :(得分:3)

您必须在keyIterator.next()之后调用keyIterator.remove(),或者在循环结束时清除所选的键集。选择器不会从该组中删除键,这取决于您。但是你还需要注意,accept()可以在非阻塞模式下返回null,并相应地进行防御性编程。