Java NIO select () kehrt ohne ausgewählte Tasten - warum?
Frage
einige Testcode Beim Schreiben habe ich festgestellt, dass Selector.select () ohne Selector.selectedKeys zurückkehren können () alle Schlüssel enthält, zu verarbeiten. Dies wird in einer engen Schleife passiert, wenn ich einen accept () ed Kanal mit
registrierenSelectionKey.OP_READ | SelectionKey.OP_CONNECT
wie die Operationen von Interesse.
Nach der Dokumentation, wählen Sie () sollte zurückgeben, wenn:
1) Es gibt Kanäle, die befolgt werden können.
2) Sie rufen explizit Selector.wakeup () - keine Tasten ausgewählt werden
.3) Sie ausdrücklich Thread.interrupt () der Thread die Auswahl tun (.) - keine Taste ausgewählt
Wenn ich keine Schlüssel nach dem select get () ich in Fällen sein muss (2) und (3). Allerdings ist mein Code nicht Aufruf Wakeup () oder unterbrechen (), um diese Erträge zu initiieren.
Alle Ideen, was dieses Verhalten verursacht?
Lösung
Kurze Antwort:. Entfernen OP_CONNECT
aus der Liste der Operationen, die Sie interessiert sind für die akzeptierte Verbindung - eine akzeptierte Verbindung ist bereits verbunden
habe ich es geschafft, das Problem zu reproduzieren, was genau sein könnte, was mit Ihnen geschieht:
import java.net.*;
import java.nio.channels.*;
public class MyNioServer {
public static void main(String[] params) throws Exception {
final ServerSocketChannel serverChannel = ServerSocketChannel.open();
serverChannel.configureBlocking(true);
serverChannel.socket().bind(new InetSocketAddress("localhost", 12345));
System.out.println("Listening for incoming connections");
final SocketChannel clientChannel = serverChannel.accept();
System.out.println("Accepted connection: " + clientChannel);
final Selector selector = Selector.open();
clientChannel.configureBlocking(false);
final SelectionKey clientKey = clientChannel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_CONNECT);
System.out.println("Selecting...");
System.out.println(selector.select());
System.out.println(selector.selectedKeys().size());
System.out.println(clientKey.readyOps());
}
}
Nachdem der obige Server eine Verbindung erhält, der erste select()
auf der Verbindung beendet, ohne zu blockieren und es gibt keine Tasten mit bereit Operationen. Ich weiß nicht, warum Java auf diese Weise verhält, aber es scheint, bekommen viele Menschen von diesem Verhalten gebissen.
Das Ergebnis ist das gleiche auf der Sun JVM 1.5.0_06 unter Windows XP sowie Sun JVM 1.5.0_05 und 1.4.2_04 unter Linux 2.6.
Andere Tipps
Der Grund dafür ist, dass OP_CONNECT
und OP_WRITE
dasselbe unter der Haube sind, so dass Sie nie für beide gleichzeitig (dito OP_ACCEPT
und OP_READ
) registriert werden sollen, und Sie sollten nie überhaupt für OP_CONNECT
registriert werden, wenn der Kanal bereits verbunden ist, , wie es in diesem Fall ist, akzeptiert wurde.
Und OP_WRITE
ist fast immer bereit, mit der Ausnahme, wenn die Socket-Sendepuffer in e-Kernel voll ist, so sollten Sie nur für dieses Register, nachdem Sie eine Länge von Null schreiben zu bekommen. So durch den bereits angeschlossenen Kanal für OP_CONNECT,
Registrierung Sie waren wirklich für OP_WRITE,
Registrierung, die bereit war, so select()
ausgelöst wurde.