J'ai créé un client de chat sous Linux en utilisant socket, et je souhaite détruire complètement la connexion. Voici les parties pertinentes du code:
int sock, connected, bytes_recieved , true = 1, pid;
char send_data [1024] , recv_data[1024];
struct sockaddr_in server_addr,client_addr;
int sin_size;
label:
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
perror("Socket");
exit(1);
}
if (setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&true,sizeof(int)) == -1)
{
perror("Setsockopt");
exit(1);
}
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(3128);
server_addr.sin_addr.s_addr = INADDR_ANY;
bzero(&(server_addr.sin_zero),8);
if (bind(sock, (struct sockaddr *)&server_addr, sizeof(struct sockaddr))== -1)
{
perror("Unable to bind");
exit(1);
}
if (listen(sock, 5) == -1)
{
perror("Listen");
exit(1);
}
printf("\nTCPServer Waiting for client on port 3128");
fflush(stdout);
connected = accept(sock, (struct sockaddr *)&client_addr,&sin_size);
//necessary code
close(sock);
goto label;
mais la fermeture (chaussette) ne semble pas fermer complètement la connexion, car après avoir été étiqueté, le code quitte en affichant le message d'erreur
Unable to bind: Address already in use
C'est que la connexion ne se reproduit plus. Quel peut être le problème? Merci d'avance.
EDIT: Ce que je veux réellement, c'est que lorsque j'exécute le script depuis le début après avoir détruit la connexion, il devrait fonctionner comme un nouveau programme. Comment puis-je le faire?
L'appel close
marque uniquement le TCP fermé. Il n'est plus utilisable par le processus. Mais le noyau peut encore contenir certaines ressources pendant un certain temps (TIME_WAIT, 2MLS etc.)).
La définition de SO_REUSEADDR devrait supprimer les problèmes de liaison.
Assurez-vous donc que la valeur de true
est vraiment non nulle lorsque vous appelez setsockopt
(un bug de débordement peut l'écraser):
true = 1;
setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&true,sizeof(int))
Il y a pid
variable est votre code. Si vous utilisez fork
(pour démarrer les processus de gestion de connexion), vous devez fermer sock
également dans le processus qui n'en a pas besoin.
Tout d'abord pour la dénomination, nous nommons donc tous les mêmes choses de la même manière:
Du côté serveur:
Le socket est passé à listen()
puis à accept()
appelons le socket d'écoute. Le socket retourné par accept()
appelons le socket accepté.
Côté client:
La socket passée à connect()
appelons la socket connectée/connectée.
Concernant votre problème:
Pour mettre fin à la connexion accept()
ed fermez le socket accepté (ce que vous appelez connecté) en utilisant d'abord shutdown()
suivi de close ()
. Pour accepter ensuite une nouvelle boucle de connexion juste avant l'appel à accept()
, ne pas passer par bind()
et listen()
à nouveau.
Arrêtez et fermez le socket d'écoute uniquement si vous souhaitez vous débarrasser de en attente connect()
s émis après accept()
retourné .
La connexion est toujours active car vous avez oublié de fermer la prise connectée. La fermeture de la prise d'écoute ne ferme pas automatiquement la prise connectée.
//necessary code
close(connected); // <---- add this line
close(sock);
goto label;
Je ne sais pas pourquoi vous obtenez EADDRINUSE. Le code a bien fonctionné sur Linux et Mac OS.
Vous devez utiliser l'appel système shutdown (2) .