web-dev-qa-db-fra.com

Erreur: adresse déjà utilisée lors de la liaison socket avec adresse, mais le numéro de port est indiqué gratuitement par `netstat`

J'ai essayé de lier mon socket (socket serveur) au numéro de port 8000. Cela a fonctionné et a fait le travail pour moi. À la fin du code, je ferme également la prise. L'instant suivant, je relance mon code et me montre que l'adresse est déjà utilisée. J'ai imprimé la signification des valeurs d'erreur strerror(errno); pour voir si mon code fonctionnait correctement à chaque point. Pour vérifier si le port est libre, je l’ai vérifié en utilisant netstat mais cela indique que le numéro de port 8000 est libre Cela m'est souvent arrivé. À chaque fois, j’attends quelques secondes de plus, puis il recommence à fonctionner. J'utilise le langage c. Alors, quelle est la raison de ce comportement de mon système d'exploitation.

Après quelques secondes de plus, je lance le code puis ça marche.

anirudh@anirudh-Aspire-5920:~/Desktop/testing$ Sudo ./a.out 
Socket Creation: Success
File open: Success
Socket Bind: Address already in use
Socket Listen: Address already in use
^C
anirudh@anirudh-Aspire-5920:~/Desktop/testing$ Sudo netstat -lntp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      1348/lighttpd   
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      984/sshd        
tcp        0      0 127.0.0.1:631           0.0.0.0:*               LISTEN      1131/cupsd      
tcp        0      0 0.0.0.0:3306            0.0.0.0:*               LISTEN      1211/mysqld     
tcp6       0      0 :::22                   :::*                    LISTEN      984/sshd        
tcp6       0      0 ::1:631                 :::*                    LISTEN      1131/cupsd      
anirudh@anirudh-Aspire-5920:~/Desktop/testing$ Sudo ./a.out 
Socket Creation: Success
File open: Success
Socket Bind: Address already in use
Socket Listen: Address already in use
^C
anirudh@anirudh-Aspire-5920:~/Desktop/testing$ 
47
Durin

J'ai rencontré le même problème aussi. C'est parce que vous fermez votre connexion à la prise, mais pas à la prise elle-même. Le socket peut entrer dans un état TIME_WAIT (pour garantir que toutes les données ont été transmises, TCP garantit la livraison si possible) et prendre jusqu'à 4 minutes pour libérer .

ou, pour une explication vraiment détaillée/technique, cliquez sur ce lien

Cela peut être agaçant pour être sûr, mais il n'y a pas vraiment de moyen de le contourner et ce n'est pas un bug.

50
icfantv

Je sais que ça fait un moment que la question a été posée mais j'ai pu trouver une solution:

int sockfd;
int option = 1;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(option));

Cela définit le socket pouvant être réutilisé immédiatement.

Je m'excuse si cela est "faux". Je ne suis pas très expérimenté avec les sockets 

20
Supamee

Essayez netstat comme ceci: netstat -ntp, sans le -l. Il affichera la connexion TCP dans l'état TIME_WAIT.

18
hipe

Comme déjà dit, votre socket entrera probablement dans l'état TIME_WAIT. Cette question est bien décrite par Thomas A. Fineici .

Pour récapituler, le processus de fermeture de socket suit le schéma ci-dessous:

 Socket closing process

Thomas dit:

En regardant le diagramme ci-dessus, il est clair que TIME_WAIT peut être évité si l'extrémité distante initie la fermeture. Donc, le serveur peut éviter les problèmes en laissant le client fermer en premier. L'application Le protocole doit être conçu de sorte que le client sache quand fermer. Le Le serveur peut se fermer en toute sécurité en réponse à un EOF du client, cependant il devra également définir un délai d'attente lorsqu'il attend un EOF au cas où le client a quitté le réseau sans grâce. Dans de nombreux cas, simplement attendre quelques secondes avant la fermeture du serveur sera suffisant.

L'utilisation de SO_REUSEADDR est couramment suggérée sur Internet, mais Thomas ajoute:

Bizarrement, utiliser SO_REUSEADDR peut en réalité conduire à des erreurs plus difficiles "d'adresse Déjà utilisées" SO_REUSADDR vous permet d'utiliser un port qui est coincé dans TIME_WAIT, mais vous ne pouvez toujours pas utiliser ce port pour établir un connexion au dernier endroit auquel il s'est connecté. Quoi? Supposons que je prenne port local 1010 et connectez-vous au port 300 de foobar.com, puis fermez localement, en laissant ce port dans TIME_WAIT. Je peux réutiliser le port local 1010 immédiatement pour vous connecter à n’importe où sauf au foobar.com port 300.

6
Jezz

Il suffit de taper

unlink [SOCKET NAME]

dans le terminal, l'erreur ne devrait plus exister.

5
programmer

Même la réponse de icfantv à cette question est déjà parfaite, il me reste encore des résultats dans mon test.

En tant que socket de serveur à l'état d'écoute, si seulement à l'état d'écoute, il accepte même les requêtes et récupère les données du côté client, mais sans aucune action d'envoi de données. Nous pouvons toujours redémarrer le serveur immédiatement après son arrêt. Mais si une action d'envoi de données se produit côté client vers le serveur, le redémarrage du même service (même port) aura cette erreur: (Adresse déjà utilisée).

Je pense que cela est dû aux principes de conception TCP/IP. Lorsque le serveur renvoie les données au client, il doit s'assurer que l'envoi des données aboutit. Pour ce faire, le système d'exploitation (Linux) doit surveiller la connexion même si l'application serveur a fermé ce socket . Mais je crois toujours au socket du noyau designer pourrait améliorer ce problème.

1
Clock ZHONG

l'erreur que j'ai reçue était:

cockpit.socket: Failed to listen on sockets: Address already in use

le correctif que j'ai découvert est:

  1. Je devais désactiver selinux
  2. dans/usr/lib/systemd/system/cockpit service, j’ai modifié la ligne :

    #ExecStartPre=/usr/sbin/remotectl certificate --ensure --user=root --group=cockpit-ws --selinux-type=etc_t
    

    à:

    #ExecStartPre=/usr/sbin/remotectl certificate --ensure --user=root --group=cockpit-ws 
    

comme vous pouvez le constater, j’ai sorti l’argument concernant selinux puis j’ai lancé:

systemctl daemon-reload
systemctl start cockpit.service

puis j'ai navigué vers:

J'ai accepté le certificat auto-signé et je pouvais me connecter avec succès au cockpit et l'utiliser normalement.

tout cela sur une machine Fedora25. Le port 9090 avait déjà été ajouté avec firewall-cmd

0
JamesAD-0

Pour AF_UNIX, vous pouvez utiliser l'appel unlink (path); après le socket close () dans l'application "serveur"

0
dr_begemot