12
votes

I wrote a server that is listening for incomming TCP connections and clients connecting to it. When I shut down the server and restart it on the same port, I sometimes get the error message EADDRINUSE when calling bind(...) (error code: 98 on Linux). This happens even though I am setting the option to reuse the socket.

The error does not happen all the time, but it seems that it happens more often when clients are connected to the server and sending data while it shuts down. I guess the problem is that there are still pending connections while the server is shut down (related topic: https://stackguides.com/questions/41602/how-to-forcibly-close-a-socket-in-time-wait).

On the server side, I am using boost::asio::ip::tcp::acceptor. I initialize it with the option "reuse_address" (see http://beta.boost.org/doc/libs/1_38_0/doc/html/boost_asio/reference/basic_socket_acceptor.html). Here is the code snippet:

using boost::asio::ip::tcp;
acceptor acceptor::acceptor(io_service);
endpoint ep(ip::tcp::v4(), port);
acceptor.open(ep.protocol());
acceptor.set_option(acceptor::reuse_address(true));
acceptor.bind(ep);
acceptor.listen();

The acceptor is closed with:

acceptor.close();

I also tried using acceptor.cancel() before that, but it had the same effect. When this error occurred, I cannot restart the server on the same port for quite some time. Restarting the network helps, but is not a permanent solution.

What am I missing?

Any help would be greatly appreciated! :)

2
does your server fork child processes? - Sam Miller
also, are you sure the socket is in TIME_WAIT state? You might want to grab the netstat -ap output when this happens. - Sam Miller
Sam, thank you very much for your input! It helped me to find the solution to my problem. It turned out that I did set the reuse address option for the acceptor, but not for all the other connections. Again, thank you very much for your help! - Alexander
I've added my comments as an answer. - Sam Miller
@Alexander I know I'm coming to this party 11 years late, but could you please explain what did you mean by "did set the reuse address option for the acceptor, but not for all the other connections."? What are these other connections? Are these sockets that have been "moved" from the acceptor's block for asynchronous processing? - user3224083

2 Answers

1
votes

These were originally a comment to the question.


does your server fork child processes? Also, are you sure the socket is in TIME_WAIT state? You might want to grab the netstat -ap output when this happens

1
votes

When you solve these problems "by force", it seems you are calling problems on your head, do not you?

There is a reason the default behavior requires you to wait, otherwise the network could for example confuse the ACK from the previous connection to be ACK for the new connection.

I would not allow this "solution" to be included in release builds in my team.

Remember, when the probability of error is very low, testing is extremely difficult!