NIO: Selector stopper block i select()
Jeg har et "sjovt" problem med Selector. Min multiplayer-server anvender multiplexed, non-blocking I/O med NIO - og følgende metode start() køres af en single-instance tråd. En anden tråd en Selector'ens accepterer inkommende klienter.Hvis jeg connecter 50 klienter (eller bare 10) går al kommunikation perfekt, men knap 1 sekund efter klienterne disconnecter (på samme tid), begynder Selector'en at loope (blokkerer ikke længere i select()) og bruger derfor 100% CPU. De følgende linier printes derfor kontinuerligt til konsollen og fylder 20 mb i log-filen på under 10 sekunder:
* Selector: out of select(30000)
* Selector: continue
private void start() {
Log.echoSystem("ClientHandler: started");
try {
selector = Selector.open();
int keysAdded;
while (noStopRequested) {
SelectionKey key = null;
try {
keysAdded = selector.select(30000);
System.out.println(" * Selector: out of select(30000)");
while (!pendingQueue.isEmpty() && handleConnections) {
SocketChannel channel = (SocketChannel)pendingQueue.remove();
SelectionKey clientKey = channel.register(selector, SelectionKey.OP_READ);
Client client = new Client(...);
clientKey.attach(client);
}
if (keysAdded == 0) {
System.out.println(" * Selector: continue");
continue;
}
Set readyKeys = selector.selectedKeys();
Iterator i = readyKeys.iterator();
while (i.hasNext()) {
try {
key = (SelectionKey)i.next();
i.remove();
if (!key.isValid())
Log.echoDebug(" * Selector: Key has been validated, but is being processed");
if (key.isReadable()) {
Client c = (Client)key.attachment();
Log.echoDebug(" * Selector: Readable: "+c.getClientID());
key.interestOps(key.interestOps() & (~SelectionKey.OP_READ));
ClientWorker worker = (ClientWorker)pool.getWorker();
worker.process(key);
} else if (key.isWritable()) {
Client c = (Client)key.attachment();
Log.echoDebug(" * Selector: Writable: "+c.getClientID());
key.interestOps(key.interestOps() & (~SelectionKey.OP_WRITE));
ClientWorker worker = (ClientWorker)pool.getWorker();
worker.process(key);
} else {
Log.echoDebug(" * Selector: Noticed, but key either readable nor writable");
}
} catch (CancelledKeyException cke) {
Client client = (Client)key.attachment();
if (client != null)
client.disconnect(cke.getMessage());
}
}
} catch (CancelledKeyException cke) {
if (key != null) {
Client client = (Client)key.attachment();
if (client != null)
client.disconnect(cke.getMessage());
}
} catch (Exception e) {
e.printStackTrace();
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
selector.close();
} catch (IOException ioe) {/* Ignore */}
}
Log.echoSystem("ClientHandler: stopped");
}
Denne metode Client.disconnct(String reason) anvendes til at disconnecte klienter med.
public void disconnect(String reason) {
synchronized(closeLock) {
if (connected) {
connected = false;
...
try {
if (key != null) {
key.cancel();
if (key.selector().isOpen())
key.selector().wakeup();
}
} catch (Exception e) { e.printStackTrace(); }
try {
channel().socket().close();
} catch (Exception e) { e.printStackTrace(); }
}
}
}
Nogen der ved hvordan problemet løses??
