Consultez ce lien
http://www.toptip.ca/2010/02/linux-eaddrnotavail-address-not.html
MODIFIER :Oui, je voulais en ajouter mais j'ai dû le couper là en raison d'une urgence
Avez-vous fermé la prise avant d'essayer de vous reconnecter ? La fermeture indiquera au système que la paire de sockets (ip/port) est maintenant libre.
Voici des éléments supplémentaires que vous pouvez également consulter :
- Si le port local est déjà connecté à l'adresse IP et au port distants donnés (c'est-à-dire qu'il existe déjà une paire de sockets identique), vous recevrez cette erreur (voir le lien du bogue ci-dessous).
- Lier une adresse de socket qui n'est pas l'adresse locale produira cette erreur. si les adresses IP d'une machine sont 127.0.0.1 et 1.2.3.4, et que vous essayez de vous lier à 1.2.3.5, vous allez obtenir cette erreur.
- EADDRNOTAVAIL :l'adresse spécifiée n'est pas disponible sur la machine distante ou le champ d'adresse de la structure du nom ne contient que des zéros.
Lien avec un bug similaire au vôtre (la réponse est proche du bas)
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4294599
Il semble que votre socket soit essentiellement bloqué dans l'un des états internes TCP et que l'ajout d'un délai de reconnexion pourrait résoudre votre problème, comme ils semblent l'avoir fait dans ce rapport de bogue.
Si vous ne souhaitez pas modifier le nombre de ports temporaires disponibles (comme suggéré par David) ou si vous avez besoin de plus de connexions que le maximum théorique, il existe deux autres méthodes pour réduire le nombre de ports utilisés. Cependant, ils sont à divers degrés des violations de la norme TCP, ils doivent donc être utilisés avec précaution.
La première consiste à activer SO_LINGER
avec un délai d'attente de zéro seconde, forçant le TCP
pile pour envoyer un paquet RST et vider l'état de la connexion. Il y a cependant une subtilité :vous devez appeler shutdown
sur le descripteur de fichier socket avant de close
, afin que vous puissiez envoyer un FIN
paquet avant le RST
paquet. Ainsi, le code ressemblera à :
shutdown(fd, SHUT_RDWR);
struct linger linger;
linger.l_onoff = 1;
linger.l_linger = 0;
// todo: test for error
setsockopt(fd, SOL_SOCKET, SO_LINGER,
(char *) &linger, sizeof(linger));
close(fd);
Le serveur ne devrait voir une réinitialisation de connexion prématurée que si le FIN
le paquet est réorganisé avec le RST
paquet.
Voir l'option TCP SO_LINGER (zéro) - quand elle est requise pour plus de détails. (Expérimentalement, peu importe où vous définissez setsockopt
.)
La seconde consiste à utiliser SO_REUSEADDR
et un bind
explicite (même si vous êtes le client), ce qui permettra à Linux de réutiliser les ports temporaires lors de l'exécution, avant qu'ils n'aient fini d'attendre. Notez que vous devez utilisez bind
avec INADDR_ANY
et le port 0
, sinon SO_REUSEADDR
n'est pas respecté. Votre code ressemblera à :
int opts = 1;
// todo: test for error
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
(char *) &opts, sizeof(int));
struct sockaddr_in listen_addr;
listen_addr.sin_family = AF_INET;
listen_addr.sin_port = 0;
listen_addr.sin_addr.s_addr = INADDR_ANY;
// todo: test for error
bind(fd, (struct sockaddr *) &listen_addr, sizeof(listen_addr));
// todo: test for addr
// saddr is the struct sockaddr_in you're connecting to
connect(fd, (struct sockaddr *) &saddr, sizeof(saddr));
Cette option est moins bonne car vous saturerez toujours les structures de données internes du noyau pour les connexions TCP selon netstat -an | grep -e tcp -e udp | wc -l
. Cependant, vous ne commencerez pas à réutiliser les ports tant que cela ne se produira pas.
Cela peut également se produire si un port invalide est donné, comme 0.