How to avoid TIME_WAIT for server sockets?

c, linux, sockets

Solution

If you follow the TCP state machine diagram, you will see that it is mandatory for the socket to transition to the TIME-WAIT state if the socket initiated sending the FIN. Using `shutdown(sockTX, 2)` without waiting for the client's FIN does exactly that.

If you want the server to wait for the client's FIN, you block on `recv()` waiting for a 0 return value first. Then, you can `close()`.

Note that unless you have duplicated the socket in some way (either with `dup*()` or with a `fork()` call), there is no need to call `shutdown()` if it is being immediately followed by a `close()`. You can just call `close()` (if the socket has been duplicated, the FIN will only be sent when the last copy is closed).

There is no need to `shutdown()` the accepting socket (`sockS`) at all.

So, I would change your server side to look something like the following to clean up the sockets:

while (recv(sockTX,...) > 0) {}
close(sockTX);

close(sockS);

Problem

I know you will mask this as duplicate (question1, question2, question3) but the answers are not what I'm looking for (and I think also other people). So, I'm refering to socket masters (I love you guys): how can I get bind error(address already in use) if I close the socket? I will describe my problem. I've got a client that communicate with a server In the server, I have two sockets: sockS (the main socket, that listens) and sockTX (the client one) If I call my programs once, the communication is fine, then I close both sockets If I recall server and client, I get the error and I've to wait the TIME_WAIT (~3 minutes seconds on Ubuntu 32bit) Why, after closing both sockets I still get bind error? There's a way to make it works without any magic (SO_REUSEADDR)? I know something in my code is wrong... Thank you everyone. That's the code: Client ``` #include <stdio.h> #include <stdlib.h> #include <ctype.h> #include <netinet/in.h> #include <sys/socket.h> #include <sys/types.h> #include <string.h> #include <netdb.h> #include <unistd.h> #include <arpa/inet.h> #define PORT 5000 #define SERVER "127.0.0.1" #define MAXLINE 128 int printMessage(char* str); int main(){ char buff[MAXLINE+1]; struct sockaddr_in server, client; struct hostent *host; int sock, n; //socklen_t len; if((sock = socket(AF_INET,SOCK_STREAM,0)) == -1){ perror("\nErrore socket()"); return -1; } client.sin_family = AF_INET; client.sin_port = htons(0); // la porta e' scelta dal sistema operativo client.sin_addr.s_addr = htonl(INADDR_ANY); if( bind(sock,(struct sockaddr*)&client, sizeof(client)) == -1){ perror("\nErrore bind()"); return -1; } server.sin_family = AF_INET; server.sin_port = htons(PORT); if((host = gethostbyname(SERVER)) == NULL ){ perror("\nErrore gethostbyname()"); return -1; } server.sin_addr = *((struct in_addr *)host->h_addr); if(connect(sock, (struct sockaddr*)&server, sizeof(server)) < 0){ perror("\nErrore connect"); return -1; } // MESSAGGIO sprintf(buff, "CTX\nclientTX\nserver\nCiao da client\n"); if(send(sock, buff, strlen(buff), 0) < 0) { perror("\nErrore sendto"); return -1; } else { printf("\nMessaggio inviato"); } if((n = recv(sock, buff, MAXLINE, 0)) < 0) { perror("\nErrore ricezione risposta"); return -1; } else { buff[n] = '\0'; int test = printMessage(buff); printf("\nEsito: %s\n", (test == 1 ? "OK" : "FAIL")); } shutdown(sock, 2); // 2 = RD_WR close(sock); return 0; } int printMessage(char* str){ int i; char* temp; printf("Mittente: "); for(i = 0; str[i] != '\n'; i++) printf("%c", str[i]); printf(" "); for(i = i+1; str[i] != '\n'; i++) printf("%c", str[i]); printf("\nDestinatario: "); for(i = i+1; str[i] != '\n'; i++) printf("%c", str[i]); temp = (char*)malloc(30 * sizeof(char)); strncpy(temp, str+i+1, 30); printf("Messaggio: %s\n", temp); if(strcmp(temp, "OK") == 0) return 1; else return 0; } ``` Server: ``` #include <stdio.h> #include <stdlib.h> #include <string.h> #include <netinet/in.h> #include <sys/socket.h> #include <sys/types.h> #include <netdb.h> #include <unistd.h> #include <arpa/inet.h> #define PORT 5000 #define SERVER "127.0.0.1" #define MAXLINE 128 int printMessage(char* str); int main() { char buff[MAXLINE+1]; struct sockaddr_in server; //, client; int sockS, sockTX, n; if((sockS = socket(AF_INET,SOCK_STREAM,0)) == -1) { perror("\nErrore socket()"); return -1; } server.sin_family = AF_INET; server.sin_port = htons(PORT); server.sin_addr.s_addr = htonl(INADDR_ANY); if(bind(sockS, (struct sockaddr *)&server, sizeof(server)) == -1) { perror("\nErrore bind()"); return -1; } if(listen(sockS, 10) == -1) { perror("\nErrore listen()"); return -1; } printf("SERVER\nInizializzazione completata!\n"); if((sockTX = accept(sockS, (struct sockaddr *)NULL, NULL)) == -1) { perror("\nErrore accept()"); return -1; } printf("Socket connesso\n"); // INVIO if((n = recv(sockTX, buff, MAXLINE, 0)) < 0) { perror("\nErrore recv()"); return -1; // BREAK?? } else { buff[n] = '\0'; printMessage(buff); } sprintf(buff, "S\nserver\nclientTX\nOK\n"); if(send(sockTX, buff, strlen(buff), 0) < 0){ perror("\nErrore send()"); return -1; // BREAK?? } else { printf("Risposta inviata\n"); } shutdown(sockTX, 2); close(sockTX); shutdown(sockS, 2); close(sockS); return 0; } int printMessage(char* str){ int i; char* temp; printf("Mittente: "); for(i = 0; str[i] != '\n'; i++) printf("%c", str[i]); printf(" "); for(i = i+1; str[i] != '\n'; i++) printf("%c", str[i]); printf("\nDestinatario: "); for(i = i+1; str[i] != '\n'; i++) printf("%c", str[i]); temp = (char*)malloc(30 * sizeof(char)); strncpy(temp, str+i+1, 30); printf("Messaggio: %s\n", temp); if(strcmp(temp, "OK\n") == 0) return 1; else return 0; } ``` Thank you everyone EDIT 1: Possible solution (not very beautiful, but just a bit more than SOCK_REUSEADDR) Try to add, before shutdown and close of the two server's socket, a sleep(1). The client will close before the server and it will work Not very beautiful, I know. Or, better, before closing the first socket inside the server, you can check if the client closed the connection (like here)

Original source

Related problems