Discussion:
[asio-users] Address already in use / reuse_address
Maximilian Szengel
2007-01-03 21:20:35 UTC
Permalink
Hi list,

I am having problems using asio. When I create a server (or take one
of the examples from the website), start it and connect to it via
telnet, then close the server (by closing all sockets, so
io_service::run returns) and then want to restart the server again, I
always get: "Address already in use." asio::error exception. I tried
setting asio::ip::tcp::acceptor::reuse_address(true), but that didn't
change anything. Any help/hint would be appreciated.

Greetings,

Max
Maximilian Szengel
2007-01-03 21:28:46 UTC
Permalink
Hi list,

I am having problems using asio. When I create a server (or take one
of the examples from the website), start it and connect to it via
telnet, then close the server (by closing all sockets, so
io_service::run returns) and then want to restart the server again, I
always get: "Address already in use." asio::error exception. I tried
setting asio::ip::tcp::acceptor::reuse_address(true), but that didn't
change anything. Any help/hint would be appreciated.

Greetings,

Max
Christopher Kohlhoff
2007-01-03 23:34:22 UTC
Permalink
Hi Max,
Post by Maximilian Szengel
Hi list,
I am having problems using asio. When I create a server (or take one
of the examples from the website), start it and connect to it via
telnet, then close the server (by closing all sockets, so
io_service::run returns) and then want to restart the server again, I
always get: "Address already in use." asio::error exception. I tried
setting asio::ip::tcp::acceptor::reuse_address(true), but that didn't
change anything. Any help/hint would be appreciated.
How are you tring to set the reuse_address option? Can you paste the
code you are using? (Note that in the latest version of asio in CVS the
option is set automatically.) What OS are you running on?

Cheers,
Chris
Maximilian Szengel
2007-01-04 01:04:51 UTC
Permalink
Hi Christopher,

thanks for your quick answer.
Post by Christopher Kohlhoff
Hi Max,
On Wed, 3 Jan 2007 22:20:35 +0100, "Maximilian Szengel"
Post by Maximilian Szengel
Hi list,
I am having problems using asio. When I create a server (or take one
of the examples from the website), start it and connect to it via
telnet, then close the server (by closing all sockets, so
io_service::run returns) and then want to restart the server again, I
always get: "Address already in use." asio::error exception. I tried
setting asio::ip::tcp::acceptor::reuse_address(true), but that didn't
change anything. Any help/hint would be appreciated.
How are you tring to set the reuse_address option? Can you paste the
code you are using? (Note that in the latest version of asio in CVS the
option is set automatically.) What OS are you running on?
I've set the option in the constructor of my Server object:

------------------------------------------------------------------------
--------
Server(asio::io_service& io_service, unsigned short port) :
io_service_(io_service), acceptor_(io_service, asio::ip::tcp::endpoint
(asio::ip::tcp::v4(), port)) {
asio::socket_base::reuse_address option(true);
acceptor_.set_option(option);

// acceptor_.set_option(asio::ip::tcp::acceptor::reuse_address(true));
}
------------------------------------------------------------------------
--------

This is the complete code:

server.hpp: http://pastebin.ca/303984
server.cpp: http://pastebin.ca/303986

I am running Mac OS X (10.4.8 intel). I just tried the cvs version
and it works there. But shouldn't it still work with the asio 0.3.7
release, or is there a known bug with it?

Greetings,

Max
Christopher Kohlhoff
2007-01-04 01:13:52 UTC
Permalink
Hi Max,

On Thu, 4 Jan 2007 02:04:51 +0100, "Maximilian Szengel"
Post by Maximilian Szengel
------------------------------------------------------------------------
--------
io_service_(io_service), acceptor_(io_service, asio::ip::tcp::endpoint
(asio::ip::tcp::v4(), port)) {
asio::socket_base::reuse_address option(true);
acceptor_.set_option(option);
// acceptor_.set_option(asio::ip::tcp::acceptor::reuse_address(true));
}
------------------------------------------------------------------------
--------
Aha, I see the problem. You are using the acceptor constructor that
automatically opens and binds the socket. This means that the
set_option() call is happening after the socket is bound, which is too
late when it comes to the reuse_address option. Look at the HTTP server
example to see how it is done with 0.3.7:

server::server(const std::string& address, const std::string& port,
const std::string& doc_root)
: io_service_(),
acceptor_(io_service_),
...
{
// Open the acceptor with the option to reuse the address (i.e.
SO_REUSEADDR).
...
acceptor_.open(endpoint.protocol());
acceptor_.set_option(asio::ip::tcp::acceptor::reuse_address(true));
acceptor_.bind(endpoint);
acceptor_.listen();
...
}

If you use the cvs version then the acceptor constructor you are using
will also set the reuse_address option before the call to bind(), which
is why that one works.

Cheers,
Chris
Gancho Manev
2007-08-20 14:26:44 UTC
Permalink
Hi Chris,

I've encountered the same problem...and have managed to workaround it
using reuse_address=true . However that does not treat the problem but
overcome the consequences of improper server stopping. By me the problem
is either OS specific, or we use ASIO in improper way.

Test case:
1. Open a server (like those in HTTP server example) in a separate thread.
2. Establish a connection to it.
3. Close the acceptor and the socket being waiting on read.
4. Join on the server thread.
5. boost::asio::write(socket, <<some_buffer>>)

- on MS Windows 2000 with ASIO 0.3.7 it works well
- on Linux 2.4.18 Intel with the same ASIO 0.3.7 there are two problems:
-- it leaves a socket in TIME_WAIT state for given time (arroung 20-30
s.), and
-- the point 5 has passed without exception. Nothing received on the
server side!!!


Any suggestions/hints are welcome.

Regards,
Gancho
Post by Christopher Kohlhoff
Hi Max,
Post by Maximilian Szengel
Hi list,
I am having problems using asio. When I create a server (or take one
of the examples from the website), start it and connect to it via
telnet, then close the server (by closing all sockets, so
io_service::run returns) and then want to restart the server again, I
always get: "Address already in use." asio::error exception. I tried
setting asio::ip::tcp::acceptor::reuse_address(true), but that didn't
change anything. Any help/hint would be appreciated.
How are you tring to set the reuse_address option? Can you paste the
code you are using? (Note that in the latest version of asio in CVS the
option is set automatically.) What OS are you running on?
Cheers,
Chris
-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
Christopher Kohlhoff
2007-08-22 11:24:49 UTC
Permalink
Post by Gancho Manev
Hi Chris,
I've encountered the same problem...and have managed to workaround it
using reuse_address=true . However that does not treat the problem but
overcome the consequences of improper server stopping. By me the problem
is either OS specific, or we use ASIO in improper way.
1. Open a server (like those in HTTP server example) in a separate thread.
2. Establish a connection to it.
3. Close the acceptor and the socket being waiting on read.
4. Join on the server thread.
5. boost::asio::write(socket, <<some_buffer>>)
- on MS Windows 2000 with ASIO 0.3.7 it works well
-- it leaves a socket in TIME_WAIT state for given time (arroung 20-30
s.), and
The TIME_WAIT state is a normal part of TCP. It is expected behaviour
that if reuse_address is false, you will be unable to start new servers
while there are sockets in TIME_WAIT.

Windows is simply taking a shortcut to avoid the TIME_WAIT state if both
the client and server are on the same machine. Evidently Linux does not
take this shortcut.
Post by Gancho Manev
-- the point 5 has passed without exception. Nothing received on the
server side!!!
I'm not sure I follow this one. Can you give more detail?

Cheers,
Chris
Gancho Manev
2007-08-22 13:29:56 UTC
Permalink
Post by Christopher Kohlhoff
Post by Gancho Manev
Hi Chris,
I've encountered the same problem...and have managed to workaround it
using reuse_address=true . However that does not treat the problem but
overcome the consequences of improper server stopping. By me the problem
is either OS specific, or we use ASIO in improper way.
1. Open a server (like those in HTTP server example) in a separate thread.
2. Establish a connection to it.
3. Close the acceptor and the socket being waiting on read.
4. Join on the server thread.
5. boost::asio::write(socket, <<some_buffer>>)
- on MS Windows 2000 with ASIO 0.3.7 it works well
-- it leaves a socket in TIME_WAIT state for given time (arroung 20-30
s.), and
The TIME_WAIT state is a normal part of TCP. It is expected behaviour
that if reuse_address is false, you will be unable to start new servers
while there are sockets in TIME_WAIT.
"The TIME_WAIT state is a normal part of TCP" if there is a listening
socket on this port, however I've performed the actions in point 3 (see
above) and even more - the process had ended when I checked the socket
states on Linux - that is suspicious stuff for me.
Post by Christopher Kohlhoff
Windows is simply taking a shortcut to avoid the TIME_WAIT state if both
the client and server are on the same machine. Evidently Linux does not
take this shortcut.
Post by Gancho Manev
-- the point 5 has passed without exception. Nothing received on the
server side!!!
I'm not sure I follow this one. Can you give more detail?
For the test code take a look at fixture_server_launcher and
rpc_integration_tests. The test that fails (the point 5 explained above)
is named "SendInStopTest" - line N 65 in rpc_integration_tests.cpp
On Windows it works correctly raising an exception: "Error during
synchronous send: An existing connection was forcibly closed by the
remote host."

I have attached the following classes:
- template <class SocketStream, class Protocol> class ConnectionImpl; in
my case:
SocketStream = boost::asio::ip::tcp::socket
Protocol = boost::asio::ip::tcp

- RPCServerImpl - particularly focus on "void end()" - delegates end to
the acceptor and gives a callback to cleanup later all already
established connections (through RpcProcessorManager)
- TCPConnectionAcceptor - focus on "void end(EndCallback callback)"
where: typedef boost::function<void ()> EndCallback; - executes the
close sequence (boost::asio::ip::tcp::acceptor::close, next
'callback()') in the Proactor thread
- RpcProcessorManager - looks like the connection_manager in ASIO HTTP
examples
- RpcProcessor - focus on "void stop()". It invokes connection->close()
and thus closes the boost::asio::ip::tcp::socket.
Post by Christopher Kohlhoff
Cheers,
Chris
Hope the code is sufficient to catch the case.

Thanks in advance,
Gancho
Post by Christopher Kohlhoff
-------------------------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems? Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >> http://get.splunk.com/
Christopher Kohlhoff
2007-09-11 08:51:53 UTC
Permalink
Post by Gancho Manev
"The TIME_WAIT state is a normal part of TCP" if there is a listening
socket on this port,
No, it's not to do with whether there is a listening socket or not.
Post by Gancho Manev
however I've performed the actions in point 3 (see
above) and even more - the process had ended when I checked the socket
states on Linux - that is suspicious stuff for me.
This stuff is managed by the kernel, so connections can remain in the
TIME_WAIT state even if the process has ended.
Post by Gancho Manev
For the test code take a look at fixture_server_launcher and
rpc_integration_tests. The test that fails (the point 5 explained above)
is named "SendInStopTest" - line N 65 in rpc_integration_tests.cpp
On Windows it works correctly raising an exception: "Error during
synchronous send: An existing connection was forcibly closed by the
remote host."
...
Post by Gancho Manev
Hope the code is sufficient to catch the case.
Unfortunately I haven't had and won't have time to go through all your
code, so it would be most helpful if you can boil it down to a very
small program.

However, I do wonder if it may simply be a sort of "race condition" in
your test. What I mean is that even though you are closing one end of
the connection, Linux might not reflect that closure on the other end of
the connection straight away.

Cheers,
Chris

Continue reading on narkive:
Loading...