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.