Reputation: 433
I'm writing a chat server in Java using Java NIO. The server accepts a connection without issue, but any time that select() returns > 0 after the first client, the server socket is always in the selected key-set even if there are no pending connections. Even if select() returns 1, the selected key-set will have 2 elements and include the server socket. This causes accept() to return null.
Any help would be greatly appreciated.
The main loop:
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
}
}
}
}
The server initialisation code:
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<>();
}
The addClient method:
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));
}
Upvotes: 1
Views: 1104
Reputation: 311023
You must call keyIterator.remove() after keyIterator.next(), or clear the selected key set at the end of the loop. The Selector doesn't remove keys from that set, it's up to you. But you also need to be aware that accept() can return null in non-blocking mode, and program defensively accordingly.
Upvotes: 4