2012-05-16 4 views
17

Ho creato un client di chat in linux tramite socket e desidero distruggere completamente la connessione. Segue le porzioni rilevanti del codice:Come distruggere completamente una connessione socket in C

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; 

ma la stretta (calza) doesnot sembrano per chiudere il distruggere completamente la connessione, perché dopo andando a 'etichetta' il codice sta uscendo con il messaggio di errore

Unable to bind: Address already in use 

Questa è la connessione non sta accadendo di nuovo. Quale può essere il problema? Grazie in anticipo.

MODIFICA: Quello che voglio veramente è che, quando eseguo lo script dall'inizio dopo aver distrutto la connessione, dovrebbe funzionare come un nuovo programma. Come posso farlo?

+0

Perché lo stai facendo? Dovresti tornare indietro prima di 'accept', non ricreare il socket del server. – Mat

+0

Perché vuoi chiudere e riaprire il socket di ascolto invece di andare in giro per 'accept()'? – dwalter

+0

possibile duplicato di [Qual è il significato di SO_REUSEADDR (opzione setsockopt) - Linux?] (Http://stackoverflow.com/questions/3229860/what-is-the-meaning-of-so-reuseaddr-setsockopt-option- linux) –

risposta

24

La chiamata close contrassegna solo il socket TCP chiuso. Non è più utilizzabile da processo. Ma il kernel può ancora contenere alcune risorse per un periodo (TIME_WAIT, 2MLS ecc.).

L'impostazione di SO_REUSEADDR dovrebbe rimuovere i problemi di associazione.

in modo da assicurarsi che il valore di true è davvero diverso da zero quando si chiama setsockopt (troppo pieno di bug può sovrascrivere):

true = 1; 
setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&true,sizeof(int)) 

C'è pid variabile è il vostro codice. Se si utilizza fork (per avviare i processi di gestione delle connessioni), è necessario chiudere sock anche nel processo che non ne ha bisogno.

-1

Bene, perché una connessione è veramente chiusa quando l'altra parte lo riconosce o dopo un certo timeout. Questo è un comportamento normale ...

EDIT: non ho fatto controllare il codice, ma dai commenti di altri utenti, si sta facendo qualcosa di sbagliato ...

0

È necessario utilizzare la chiamata di sistema shutdown(2).

+1

L'ho provato ma ancora senza fortuna. La connessione non viene distrutta. –

1

Prima per il nameing, in modo che tutti noi nome le cose stesse la stessa: laterali

Server:

La presa passato a listen() e poi a accept() chiamiamolo il socket di ascolto. Il socket restituito da accept() chiama il socket accettato.

lato client:

La presa passato a connect() Chiamiamo il collegamento/presa collegata.


Per quanto riguarda il problema:

di terminare la connessione accept() ndr chiudere il socket accettato (quello che chiamata connessa) dal primo utilizzo shutdown() seguito da close(). Per accettare nuovamente un nuovo ciclo di connessione prima della chiamata a accept(), non fare passare di nuovo tramite bind() e listen().

Solo arresto e chiudere il socket di ascolto, se si vuole sbarazzarsi di attesaconnect() s emesse dopo accept() restituiti.

1

La connessione è ancora attiva perché si è dimenticato di chiudere il socket collegato. La chiusura della presa di ascolto non chiude automaticamente la presa collegata.

//necessary code 
close(connected); // <---- add this line 
close(sock); 
goto label; 

Non sono sicuro del motivo per cui stai ricevendo EADDRINUSE. Il codice ha funzionato bene sia su Linux che su Mac OS.