Question

En écrivant du code de test, j'ai constaté que Selector.select () peut renvoyer sans Selector.selectedKeys () contenant les clés à traiter. Cela se produit dans une boucle serrée lorsque je crée un canal accepté () avec

SelectionKey.OP_READ | SelectionKey.OP_CONNECT

en tant qu'opérations d'intérêt.

En fonction de la documentation, select () devrait revenir lorsque:

1) Certains canaux peuvent être utilisés.

2) Vous appelez explicitement Selector.wakeup () - aucune clé n'est sélectionnée.

3) Vous explicitement Thread.interrupt () le thread faisant le select () - aucune clé n'est sélectionnée.

Si je n’obtiens aucune clé après select (), je dois être dans les cas (2) et (3). Cependant, mon code n’appelle pas wakeup () ni interruption () pour initialiser ces retours.

Avez-vous des idées sur la cause de ce comportement?

Était-ce utile?

La solution

Réponse courte: supprimez OP_CONNECT de la liste des opérations qui vous intéressent pour la connexion acceptée - une connexion acceptée est déjà connectée.

J'ai réussi à reproduire le problème, ce qui pourrait être exactement ce qui vous arrive:

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());
  }
}

Une fois que le serveur ci-dessus a reçu une connexion, le tout premier select () de la connexion se ferme sans blocage et aucune clé n'est prête. Je ne sais pas pourquoi Java se comporte de cette façon, mais il semble que beaucoup de gens soient piqués par ce comportement.

Le résultat est identique sur la machine virtuelle Java 1.5.0_06 de Sun sous Windows XP, ainsi que sur la machine virtuelle Java 1.5.0_05 et 1.4.2_04 sous Linux 2.6.

Autres conseils

La raison en est que OP_CONNECT et OP_WRITE sont la même chose sous le capot, de sorte que vous ne devriez jamais être enregistré pour les deux simultanément (idem OP_ACCEPT et OP_READ ), et vous ne devriez jamais être enregistré pour OP_CONNECT lorsque le canal est déjà connecté, comme c'est le cas dans ce cas, après avoir été accepté.

Et OP_WRITE est presque toujours prêt, sauf lorsque le tampon d’envoi du socket dans le noyau est plein. Vous ne devez donc vous enregistrer pour cela qu'après avoir obtenu une écriture de longueur nulle. Donc, en enregistrant le canal déjà connecté pour OP_CONNECT, , vous vous enregistriez réellement pour OP_WRITE, qui était prêt, donc select () a été déclenché.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top