Les concepts de TCP non-bloquant étudiés pour les serveurs s'appliquent :
Il y a 2 nouveautés :
socketChannel.connect()
;
En mode bloquant, socketChannel.connect
bloque jusqu'à l'établissement de la connexion.
En mode non-bloquant,
socketChannel.connect
initie la connexion ;SelectionKey.OP_CONNECT
auprès d'un sélecteur, le sélecteur notifie quand la connexion est établie ;boolean socketChannel.finishConnect
permet de tester que la connexion a bien été établie.var sc = SocketChannel.open(); sc.configureBlocking(false); sc.connect(serverAddress); var sKey = sc.register(selector, SelectionKey.OP_CONNECT);
L'appel à
sc.connect(serverAddress)
initie la connexion.
Le sélecteur nous préviendra quand la connexion est établie.
while (!Thread.interrupted()) { selector.select(this::treatKey); }
avec
void treatKey(SelectionKey key) { if (key.isValid() && key.isConnectable()) { doConnect(key); } if (key.isValid() && key.isWritable()) { doWrite(key); } if (key.isValid() && key.isReadable()) { doRead(key); } }
Attention aux exceptions...
doConnect
private void doConnect(SelectionKey key) throws IOException { if (!sc.finishConnect()) { return; // the selector gave a bad hint } key.interestOps(SelectionKey.OP_READ); }
Dans un client non-bloquant, les trames à envoyer au serveur viennent en général d'un autre thread que celui exécutant la boucle de sélection :
Problème : les sélecteurs ne sont pas thread-safe !
Par exemple, on ne peut pas modifier les interestOps
des clés, appeler register
, ... dans un autre thread que celui qui exécute la boucle de sélection.
La seule méthode thread-safe est selector.wakeup()
qui force le selector
à sortir de selector.select
.