Parfois, lors de l'envoi d'une grande quantité de données via SocketChannel.write(), le tampon TCP sous-jacent est rempli, et je dois réessayer continuellement write() jusqu'à ce que les données sont toutes envoyées.Problème de thread Java NIO avec SocketChannel.write()
Alors, je pourrais avoir quelque chose comme ceci:
public void send(ByteBuffer bb, SocketChannel sc){
sc.write(bb);
while (bb.remaining()>0){
Thread.sleep(10);
sc.write(bb);
}
}
Le problème est que la question de temps en temps avec un grand ByteBuffer et un tampon TCP sous-jacente débordement signifie que cet appel à envoyer() bloquera pour un inattendu quantité de temps. Dans mon projet, il y a des centaines de clients connectés simultanément, et un retard causé par une connexion socket peut amener l'ensemble du système à une analyse jusqu'à ce que ce retard d'un SocketChannel soit résolu. Lorsqu'un retard survient, il peut provoquer une réaction en chaîne du ralentissement dans d'autres zones du projet, et une faible latence est importante.
J'ai besoin d'une solution qui prendra en charge ce problème de débordement de tampon TCP de manière transparente et sans que tout bloque lorsque plusieurs appels à SocketChannel.write() sont nécessaires. J'ai envisagé de mettre send() dans une classe séparée en étendant Thread afin qu'il s'exécute comme son propre thread et ne bloque pas le code appelant. Cependant, je suis préoccupé par le surcoût nécessaire pour créer un thread pour CHAQUE connexion socket que je maintiens, surtout quand 99% du temps, SocketChannel.write() réussit au premier essai, ce qui signifie qu'il n'y a pas besoin que le thread soit là . (En d'autres termes, mettre send() dans un thread séparé n'est vraiment nécessaire que si la boucle while() est utilisée - seulement dans les cas où il y a un problème de buffer, peut-être 1% du temps). seulement 1% du temps, je n'ai pas besoin de la surcharge d'un thread pour l'autre 99% des appels à envoyer(). J'espère que cela a du sens ... Je pourrais vraiment utiliser quelques suggestions. Merci!
Le sommeil a du sens si le socket n'est pas bloquant avec un buffer complet, ce que ne dit pas l'original. –
Il suppose que le tampon prendra toujours au moins 10 ms à effacer. Personnellement, si le tampon ne disparaît pas presque immédiatement, soit le tampon est trop petit, soit le lecteur est trop lent. Je fermerais la connexion. –
Si le tampon d'octets dans l'exemple est plus grand que le tampon de sortie du socket du noyau, le code est inefficace, car il peut probablement écrire plus vite que la carte réseau peut écrire et ainsi se saturer. En 10ms de sommeil, la carte réseau pourrait écrire environ 1 Mo sur un réseau de 1 Go, bien plus que la taille de tampon de sortie de socket typique. Si le bytebuffer n'est que de quelques Ko c'est probablement le lecteur qui est trop lent, alors il est judicieux de mettre un peu en pause, en utilisant OP_WRITE est plus complexe mais éviterait de bloquer un thread pour dormir ainsi que buffer underruns. –