web-dev-qa-db-fra.com

"Java.net.BindException: adresse déjà utilisée" lors d'une tentative de création et de destruction rapides de socket pour les tests de charge

J'essaie de charger le test d'un serveur Java en ouvrant un grand nombre de connexions socket au serveur, en authentifiant, en fermant la connexion, puis en répétant. Mon application fonctionne très bien pendant un certain temps mais finalement j'obtiens :

Java.net.BindException: adresse déjà utilisée: connect

Selon la documentation que j'ai lue, la raison en est que les sockets fermées occupent toujours l'adresse locale qui leur est attribuée pendant une période de temps après l'appel de close (). Cela dépend du système d'exploitation mais peut être de l'ordre de quelques minutes. J'ai essayé d'appeler setReuseAddress(true) sur le socket en espérant que son adresse serait réutilisable immédiatement après l'appel de close(). Malheureusement, cela ne semble pas être le cas.

Mon code pour la création de socket est:

Socket socket = new Socket();
socket.setReuseAddress(true);
socket.connect(new InetSocketAddress(m_Host, m_port));

Mais je reçois toujours cette erreur:

Java.net.BindException: adresse déjà utilisée: connectez-vous après un certain temps.

Existe-t-il un autre moyen d'accomplir ce que j'essaie de faire? Je voudrais par exemple: ouvrir 100 sockets, les fermer tous, ouvrir 200 sockets, les fermer tous, ouvrir 300, etc. jusqu'à un maximum de 2000 sockets environ.

Toute aide serait grandement appréciée!

27
bradforj287

Vous épuisez l'espace des ports sortants en ouvrant autant de sockets sortants dans la période TIME_WAIT de deux minutes. La première question que vous devez vous poser est la suivante: cela représente-t-il un test de charge réaliste? Un vrai client va-t-il vraiment faire ça? Sinon, il vous suffit de réviser votre méthodologie de test.

BTW SO_LINGER est le nombre de secondes pendant lesquelles application attendra pendant close () pour que les données soient vidées. Il est normalement nul. Le port restera de toute façon pendant l'intervalle TIME_WAIT si c'est la fin qui a émis la fermeture. Ce n'est pas la même chose. Il est possible d'abuser de l'option SO_LINGER pour corriger le problème. Cependant, cela entraînera également un comportement exceptionnel chez le pair et là encore, ce n'est pas le but d'un test.

20
user207421

Ne pas utiliser bind () mais setReuseAddress (true) est juste bizarre, j'espère que vous comprenez les implications de setReuseAddress (et le point de). 100-2000 n'est pas un grand nombre de sockets à ouvrir, cependant le serveur auquel vous essayez de vous connecter (car il ressemble à la même paire addr/port ), peut simplement les supprimer avec un carnet de commandes normal de 50.

Edit: si vous avez besoin d'ouvrir rapidement plusieurs sockets (ermm scan scan?), Je très recommande fortement d'utiliser NIO et connect ()/finishConnect () + Selector. L'ouverture de 1000 sockets dans le même thread est tout simplement lente. Vous avez peut-être besoin de finishConnect () dans les deux cas dans votre code.

1
bestsss