32

I have made a chat client in linux using socket, and i wish to destroy the connection completely. Following is the relevant portions of the 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;

but the close(sock) doesnot seem to close the destroy the connection completely, because after going to 'label' the code is exiting showing the error message

Unable to bind: Address already in use

That is the connection is not happening again. What can the problem be? Thanks in advance.

EDIT: What I actually want is, when I run the script from the beginning after destroying the connection, it should run as a fresh program. How can I do it?

Harikrishnan
  • 7,765
  • 13
  • 62
  • 113
  • 1
    Why are you doing that? You should loop back to just before the `accept`, not re-create the server socket. – Mat May 16 '12 at 13:50
  • 1
    Why do you want to close and reopen the listening socket instead of looping around `accept()` ? – dwalter May 16 '12 at 13:50
  • possible duplicate of [What is the meaning of SO_REUSEADDR (setsockopt option) - Linux?](http://stackoverflow.com/questions/3229860/what-is-the-meaning-of-so-reuseaddr-setsockopt-option-linux) – n. m. could be an AI May 16 '12 at 13:56
  • When I did that, I got the reply `You are connected to , ` which was the printf i gave to check if the connection is established or not. The connection should be established only if the client runs the program but it is established even without the client running the program on client side. What should I do now? – Harikrishnan May 16 '12 at 14:00
  • 1
    "I got the reply *You are connected to , *" --- where from? Your code does not contain that. Please show the relevant code. – n. m. could be an AI May 16 '12 at 14:03
  • `printf("\n You are connected to %s , %d)", inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port));` This is placed right below `accept()`. – Harikrishnan May 16 '12 at 14:06
  • http://serverfault.com/questions/329845/how-to-forcibly-close-a-socket-in-time-wait – Ciro Santilli OurBigBook.com Feb 27 '16 at 12:03

6 Answers6

49

The close call only marks the TCP socket closed. It is not usable by process anymore. But kernel may still hold some resources for a period (TIME_WAIT, 2MLS etc stuff).

Setting of SO_REUSEADDR should remove binding problems.

So be sure that value of true is really non-zero when calling setsockopt (overflow bug may overwrite it):

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

There is pid variable is your code. If you use fork (for starting connection handling processs), then you should close sock also in the process which does not need it.

SKi
  • 8,007
  • 2
  • 26
  • 57
9

First for the naming, so we all name the same things the same:

Server side:

The socket passed to listen() and then to accept() let's call the listening socket. The socket returned by accept() let's call the accepted socket.

Client side:

The socket passed to connect() let's call the connecting/connected socket.


Regarding your issue:

To terminate the accept()ed connection close the accepted socket (what you call connected) by optionally first using shutdown() followed by close ().

To then accept a new connection loop right back before the call to accept(), do not go via bind() and listen() again.

Only shutdown and close the listening socket if you want to get rid of pending connect()s issued after accept() returned.

alk
  • 69,737
  • 10
  • 105
  • 255
  • 1
    The shutdown is not necessary before closing. Close implies shutdown unless the SD is shared with another process, which is not the case here. Amd you never need to shutdown the listening socket. – user207421 Dec 08 '19 at 21:40
  • @user207421: Amended my answer accordingly. – alk Dec 09 '19 at 12:36
8

The connection is still active because you forgot to close the connected socket. Closing the listening socket does not automatically close the connected socket.

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

I am not sure though why you are getting EADDRINUSE. The code worked fine on both linux and mac os.

enobufs
  • 860
  • 1
  • 7
  • 12
0

You should use the shutdown(2) system call.

Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
0

The correct answer is about SO_REUSEADDR.

If you are the listener, and accept a connection, you must call shutdown() before close() (at least on Linux). If you just call close(), you will not ACK the FIN that the client is sending to close the connection, and the client may get stuck in a CLOSE_WAIT state.

Eric Aya
  • 69,473
  • 35
  • 181
  • 253
-3

Well, because a connection is really closed when the other party acknowledges it or after a certain timeout. This is normal behaviour...

EDIT: I did not actually check your code but from other users' comments, you are doing something wrong...

Malkocoglu
  • 2,522
  • 2
  • 26
  • 32