Java Language
NIO - Networking
Ricerca…
Osservazioni
SelectionKey
definisce le diverse operazioni e informazioni selezionabili tra il selettore e il canale . In particolare, l' allegato può essere utilizzato per memorizzare informazioni relative alla connessione.
La gestione di OP_READ
è piuttosto semplice. Tuttavia, è necessario prestare attenzione quando si ha a che fare con OP_WRITE
: la maggior parte delle volte, i dati possono essere scritti in socket, quindi l'evento continuerà a sparare. Assicurati di registrare OP_WRITE
solo prima di voler scrivere i dati (vedi la risposta ).
Inoltre, OP_CONNECT
dovrebbe essere cancellato una volta che il canale è stato connesso (perché, beh, è connesso. Vedi questo e quella risposte su SO). Quindi la rimozione di OP_CONNECT
dopo finishConnect()
riuscita.
Utilizzo del selettore per attendere gli eventi (ad esempio con OP_CONNECT)
NIO è apparso in Java 1.4 e ha introdotto il concetto di "Canali", che dovrebbero essere più veloci del normale I / O. Dal punto di vista della rete, SelectableChannel
è il più interessante in quanto consente di monitorare diversi stati del Canale. Funziona in modo simile alla chiamata di sistema C select()
: veniamo riattivati quando si verificano determinati tipi di eventi:
- connessione ricevuta (
OP_ACCEPT
) - connessione realizzata (
OP_CONNECT
) - dati disponibili in FIFO letto (
OP_READ
) - i dati possono essere spinti per scrivere FIFO (
OP_WRITE
)
Permette la separazione tra la rilevazione di I / O socket (qualcosa può essere letto / scritto / ...) e l' esecuzione dell'I / O (lettura / scrittura / ...). Soprattutto, tutto il rilevamento I / O può essere eseguito in un singolo thread per più socket (client), mentre l'esecuzione dell'I / O può essere gestita in un pool di thread o in qualsiasi altro luogo. Ciò consente a un'applicazione di scalare facilmente il numero di client connessi.
Il seguente esempio mostra le basi:
- Crea un
Selector
- Crea un
SocketChannel
- Registrare lo
SocketChannel
nelSelector
- Loop con il
Selector
per rilevare gli eventi
Selector sel = Selector.open(); // Create the Selector
SocketChannel sc = SocketChannel.open(); // Create a SocketChannel
sc.configureBlocking(false); // ... non blocking
sc.setOption(StandardSocketOptions.SO_KEEPALIVE, true); // ... set some options
// Register the Channel to the Selector for wake-up on CONNECT event and use some description as an attachement
sc.register(sel, SelectionKey.OP_CONNECT, "Connection to google.com"); // Returns a SelectionKey: the association between the SocketChannel and the Selector
System.out.println("Initiating connection");
if (sc.connect(new InetSocketAddress("www.google.com", 80)))
System.out.println("Connected"); // Connected right-away: nothing else to do
else {
boolean exit = false;
while (!exit) {
if (sel.select(100) == 0) // Did something happen on some registered Channels during the last 100ms?
continue; // No, wait some more
// Something happened...
Set<SelectionKey> keys = sel.selectedKeys(); // List of SelectionKeys on which some registered operation was triggered
for (SelectionKey k : keys) {
System.out.println("Checking "+k.attachment());
if (k.isConnectable()) { // CONNECT event
System.out.print("Connected through select() on "+k.channel()+" -> ");
if (sc.finishConnect()) { // Finish connection process
System.out.println("done!");
k.interestOps(k.interestOps() & ~SelectionKey.OP_CONNECT); // We are already connected: remove interest in CONNECT event
exit = true;
} else
System.out.println("unfinished...");
}
// TODO: else if (k.isReadable()) { ...
}
keys.clear(); // Have to clear the selected keys set once processed!
}
}
System.out.print("Disconnecting ... ");
sc.shutdownOutput(); // Initiate graceful disconnection
// TODO: emtpy receive buffer
sc.close();
System.out.println("done");
Darebbe il seguente risultato:
Initiating connection
Checking Connection to google.com
Connected through 'select()' on java.nio.channels.SocketChannel[connection-pending remote=www.google.com/216.58.208.228:80] -> done!
Disconnecting ... done