Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

bind() with SO_REUSEADDR fails

Tags:

c

sockets

bind

My task is to implement a two player game played between two computers connected via TCP. One of the requirement is that only the winner is given the choice play again or not. In case the server wins and decides not to play further, the client should restart as a server and accept new connections.

My approach: If game LOST (in client mode), close sockfd and recreate another one. Then use setsockopt to allow rebinding using SO_REUSEADDR, then calling bind.

int yes = 1;
if ( setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1 )
{
    perror("setsockopt");
}

if ( bind(sockfd, (struct sockaddr*)&svr, sizeof(svr) ) == -1 )
{
    perror("server: bind");
}

But still, I'm getting the same "Address already in use" error. I've tried sleeping for 150 seconds before recreating the socket and this method works.

NOTE: I'm testing this on the same PC. It may work on two linked PCs but its a necessity to make it work on the same PC. Please help.

like image 902
tecfreak Avatar asked Nov 30 '11 18:11

tecfreak


People also ask

How do I fix bind failed address already in use?

The Error “address already in use” occurred because some process was already running on the same port. So we can resolve the issue just by killing the process. To stop the process, we need the process ID (PID), which we can fetch using the lsof command.

What does bind failed mean?

The error usually means that the port you are trying to open is being already used by another application. Try using netstat to see which ports are open and then use an available port.

What does So_reuseaddr mean?

SO_REUSEADDR allows your server to bind to an address which is in a. TIME_WAIT state. This socket option tells the kernel that even if this port is busy (in the TIME_WAIT state), go ahead and reuse it anyway. If it is busy, but with another state, you will still get an address already in use error.

What is socket So_reuseaddr?

The SO_REUSEADDR socket option allows a socket to forcibly bind to a port in use by another socket. The second socket calls setsockopt with the optname parameter set to SO_REUSEADDR and the optval parameter set to a boolean value of TRUE before calling bind on the same port as the original socket.


2 Answers

SO_REUSEADDR only allows you to simultaneously bind to a more a specific address, i.e. first server listens on INADDR_ANY (all interfaces) and subsequent servers listen on different specific interface addresses.

Second scenario is when listening TCP socket accepts a connection, which is kept in use, but the listening socket itself is closed and then re-opened - say parent server process exits and starts again.

In both cases you need to always set SO_REUSEADDR option on the listening socket before you call bind(2).

like image 61
Nikolai Fetissov Avatar answered Oct 20 '22 17:10

Nikolai Fetissov


Since you are running this on the same system, it sounds like you have a race condition. The client is trying to bind() the socket just before the server has closed it (assuming both server and client are setting SO_REUSEADDR on their sockets).

You need to implement some kind of handshake that allows the server to inform the client after it has closed the listening socket - perhaps the server should close the listening socket before it closes the active socket from the last game?

like image 42
caf Avatar answered Oct 20 '22 17:10

caf