web-dev-qa-db-fra.com

Comment détruire complètement une connexion socket en C

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?

22
Harikrishnan

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.

31
SKi

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é .

6
alk

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.

4
enobufs

Vous devez utiliser l'appel système shutdown (2) .

1