Domanda

Nello scrivere un codice di prova ho scoperto che Selector.select () può restituire senza Selector.selectedKeys () contenente alcuna chiave da elaborare. Questo sta accadendo in un ciclo stretto quando registro un canale accept () ed con

SelectionKey.OP_READ | SelectionKey.OP_CONNECT

come operazioni di interesse.

Secondo i documenti, selezionare () dovrebbe tornare quando:

1) Ci sono canali su cui si può agire.

2) Chiami esplicitamente Selector.wakeup () - nessuna chiave è selezionata.

3) Hai esplicitamente Thread.interrupt () il thread che fa il select () - nessuna chiave è selezionata.

Se non ricevo i tasti dopo la selezione () devo essere nei casi (2) e (3). Tuttavia, il mio codice non sta chiamando wakeup () o interrupt () per avviare questi ritorni.

Qualche idea su cosa sta causando questo comportamento?

È stato utile?

Soluzione

Risposta breve: rimuovi OP_CONNECT dall'elenco delle operazioni a cui sei interessato per la connessione accettata - una connessione accettata è già connessa.

Sono riuscito a riprodurre il problema, che potrebbe essere esattamente quello che ti sta succedendo:

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

Dopo che il server sopra ha ricevuto una connessione, il primissimo select () sulla connessione si chiude senza bloccare e non ci sono chiavi con operazioni pronte. Non so perché Java si comporti in questo modo, ma sembra che molte persone vengano morse da questo comportamento.

Il risultato è lo stesso su JVM 1.5.0_06 di Sun su Windows XP e su JVM 1.5.0_05 e 1.4.2_04 di Sun su Linux 2.6.

Altri suggerimenti

Il motivo è che OP_CONNECT e OP_WRITE sono la stessa cosa sotto il cofano, quindi non dovresti mai essere registrato per entrambi contemporaneamente (idem OP_ACCEPT e OP_READ ) e non dovresti mai essere registrato per OP_CONNECT quando il canale è già collegato, come in questo caso, essendo stato accettato.

E OP_WRITE è quasi sempre pronto, tranne quando il buffer di invio socket in e kernel è pieno, quindi dovresti registrarti solo dopo aver ottenuto una scrittura di lunghezza zero. Quindi registrando il canale già collegato per OP_CONNECT, ti stavi davvero registrando per OP_WRITE, che era pronto, quindi select () è stato attivato.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top