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)
If too many sockets are in TIME_WAIT you will find it difficult to establish new outbound connections due to there being a lack of local ports that can be used for the new connections.
From Network perspective, TCP TIME_WAIT status is just a normal behavior that after closing the session, TCP stack will hold the high port for little more time to ensure the other side receive the last FIN-ACK packet and no more data will be received in this conversation.
The TIME-WAIT state is a mechanism in TCP/IP stacks that keeps sockets open after an application shuts down the sockets. By default, this state lasts for 60 seconds to ensure complete data transmission between the server and the client.
TIME_WAIT means it's waiting for a reply or connection. this often happens when a port is activated and the connection has not yet. been established.
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);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With