Socket connect/disconnect, ReuseAddress, and TIME_WAIT

R

Rob Gravereaux

Visual Studio 2005, .Net 2.0, Vista, XP.

I have a client Tcp socket that is bound to a particular port and connecting
to a remote host. In order to allow reconnects I'm setting the ReuseAddress
socket option. This is somewhat dubious I know, but...

With the ReuseAddress option, a bind to a local port in a TIME_WAIT state
(netstat -a) does succeed, but the socket connect is failing with the 'Only
one usage of each socket address...' message. For example, in the following
code, call Connect(), then Disconnect(), then Connect() again (within the
TIME_WAIT period, about 4 minutes) and s.Connect(...) throws an exception.

There are a few posts I've seen that specify using the ReuseAddress socket
option in this scenario. Am I missing something? How can I successfully bind
to a local port that is already in a TIME_WAIT state and successfully
connect?

Some sample code...

private bool m_bConnected;

private Socket m_Socket;

private void Connect()
{
string sLocalHost = txtInboundLocalHost.Text;
int iLocalPort = int.Parse(txtInboundLocalPort.Text);
string sRemoteHost = txtInboundRemoteHost.Text;
int iRemotePort = int.Parse(txtInboundRemotePort.Text);

// Create socket and set options.
Socket s = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
s.SetSocketOption(SocketOptionLevel.Socket,
SocketOptionName.ReuseAddress, (int)1);

// Create local endpoint if desired.
if(!string.IsNullOrEmpty(sLocalHost))
{
// Use specified interface and port on local machine.
IPAddress ip;
if (IPAddress.TryParse(sLocalHost, out ip)
&& (ip.AddressFamily ==
System.Net.Sockets.AddressFamily.InterNetwork))
{
s.Bind(new IPEndPoint(ip, iLocalPort));
}
else
throw new ApplicationException("Not a valid IP
Address.");
}
else if(iLocalPort > 0)
{
// Use specified port on local machine, all interfaces.
s.Bind(new IPEndPoint(IPAddress.Any, iLocalPort));
}
// Otherwise, use default host & port...

// Connect to remote. This errors if port is in TIME_WAIT state.
s.Connect(sRemoteHost, iRemotePort);

m_Socket = s;
m_bConnected = true;
}

private void Disconnect()
{
if (m_bConnected)
{
// Shutdown socket and allow reuse.
m_Socket.Shutdown(SocketShutdown.Both);
m_Socket.Disconnect(true);
}
m_bConnected = false;
}

TIA.

Rob Gravereaux
 
O

Olie

I think ReuseAddress only applies to a UDP sockets and is not
applicable for TCP. The normal way to use TCP is to have a listener
socket from which you spawn the communications sockets on another
port.
 
P

Peter Duniho

Visual Studio 2005, .Net 2.0, Vista, XP.

I have a client Tcp socket that is bound to a particular port and
connecting to a remote host. In order to allow reconnects I'm setting
the ReuseAddress socket option. This is somewhat dubious I know, but...

With the ReuseAddress option, a bind to a local port in a TIME_WAIT
state (netstat -a) does succeed, but the socket connect is failing with
the 'Only one usage of each socket address...' message. For example, in
the following code, call Connect(), then Disconnect(), then Connect()
again (within the TIME_WAIT period, about 4 minutes) and s.Connect(...)
throws an exception.

There are a few posts I've seen that specify using the ReuseAddress
socket option in this scenario. Am I missing something? How can I
successfully bind to a local port that is already in a TIME_WAIT state
and successfully connect?

Contrary to the other reply, ReuseAddress is valid on TCP sockets.

That said, it's not a panacea. Even using ReuseAddress, you won't be
able to accept a connection from the same client that was connected
when the previous connection was reset. You'll still need to be able
to tolerate a delay until the original TIME_WAIT socket has been
cleaned up.

The better solution is simply to make sure that your connections go
through a graceful shutdown before closing the socket, using the
Socket.Shutdown() method. Note that that means not only do you call
Shutdown(), but you don't close the socket until you've received
notification that the graceful shutdown has completed (for example,
receiving 0 bytes). I.e. don't just call Shutdown() followed
immediately by a call to Disconnect().

For what it's worth, there are a couple of Winsock newsgroups that,
while not .NET-specific, are sometimes read by people who know a lot
more about Winsock and networking in general than you'll find here
(like me :) ).

Pete
 
P

Peter Duniho

[...]
For what it's worth, there are a couple of Winsock newsgroups that,
while not .NET-specific, are sometimes read by people who know a lot
more about Winsock and networking in general than you'll find here
(like me :) ).

I meant to provide the names of those newsgroups. Sorry. :)

alt.winsock.programming
comp.os.ms-windows.programmer.tools.winsock

The former is much more active than the latter, but you can find
quality help in either, especially if you're patient.

Pete
 
R

Rob Gravereaux

I'll try those other newsgroups. Thanks.

Can you point me to a discussion of 'graceful shutdown'. AFAIK, Shutdown and
Close (Disconnect) is the way to close a socket. From the Socket class
documentation:

When you are finished sending and receiving data, use the Shutdown method to
disable the Socket. After calling Shutdown, call the Close method to release
all resources associated with the Socket.

I was looking at the connect/disconnect packets with WireShark and saw that
the sample code I was using was producing the proper(?) FIN, ACK exchange to
close the socket. IE, on the other hand, seems to send RST, ACK when closing
its sockets.
 
P

Peter Duniho

I'll try those other newsgroups. Thanks.

Can you point me to a discussion of 'graceful shutdown'. AFAIK,
Shutdown and Close (Disconnect) is the way to close a socket. From the
Socket class documentation:

When you are finished sending and receiving data, use the Shutdown
method to disable the Socket. After calling Shutdown, call the Close
method to release all resources associated with the Socket.

Unfortunately, the MSDN documentation does a better job describing how
to use .NET features that are unique to .NET. I've noticed that where
..NET wraps some other functionality, the docs tend to assume you're
already familiar with that functionality.

For this particular issue, I recommend the usual Winsock resources,
which would include MSDN's docs for Winsock itself, as well as the
Winsock FAQ. You can start here:
http://msdn2.microsoft.com/en-us/library/ms740481.aspx

Check out also:
http://msdn2.microsoft.com/en-us/library/ms740673.aspx
http://tangentsoft.net/wskfaq/
I was looking at the connect/disconnect packets with WireShark and saw
that the sample code I was using was producing the proper(?) FIN, ACK
exchange to close the socket. IE, on the other hand, seems to send RST,
ACK when closing its sockets.

That could be simply due to the nature of the HTTP connections. IE is
likely to not be the one to initiate a connection closure, since at
least with the simplest HTTP usage, the client just receives data until
the server closes the connection. So the server would call shutdown(),
but the client would just close the socket when it receives 0 bytes.

I admit, I don't know a whole lot about HTTP, and I don't know how the
feature of reusing HTTP connections affects this behavior (e.g. is the
server still responsible for closing the connection?). But the basic
issue remains: you should call Shutdown() and then not close the socket
until you have received notification that you've gotten all the data
from the socket (i.e. received 0 bytes).

Pete
 
R

Rob Gravereaux

My mention of IE is only in terms of it being a TCP client. AFAIK, the
original HTTP protocol stated the server closes the socket after sending the
response. More current versions of HTTP allow the socket to stay open and
the client can make further http requests. Wireshark shows IE on my machine
keeping sockets open until IE shuts down. At that point IE closes all open
sockets via RST, ACK which is a hard shutdown. In this case the socket on
the client PC does not enter a TIME_WAIT state, and can immediately be used
again in a Socket.Bind() and Socket.Connect().

The ftp command line utility also seems to exhibit this behaviour. When
quitting it closes the socket with RST, ACK. The socket on the client PC
does not enter a TIME_WAIT state.

I did some further work with the .Net socket code shown earlier in this
thread. Your comment earlier about reading from the socket while closing is
echoed in the MSDN docs for the Winsock 2 shutdown function
(http://msdn2.microsoft.com/en-us/library/ms740481.aspx), however the .Net
docs for Socket.Shutdown
(http://msdn2.microsoft.com/en-us/library/system.net.sockets.socket.shutdown.aspx)
state the proper way to close a socket is to call Socket.Shutdown() followed
by Socket.Close(). This results in the FIN,ACK exchange, and is a graceful
shutdown of the socket. The socket on the client PC then enters a TIME_WAIT
state and cannot be used in a Socket.Bind() and Socket.Connect() until the
TIME_WAIT period expires.

Replacing the Socket.Shutdown() and Socket.Close() with just Socket.Close()
results in an RST,ACK. This is a hard shutdown. The port on the client does
NOT enter a TIME_WAIT state and the port can immediately be used in a
Socket.Bind() and Socket.Connect(). Using Socket.Close(int) specifying a
timeout value results in a graceful shutdown. Using the previous code:

Graceful shutdown:
private void Disconnect()
{
if (m_bConnected)
{
// Graceful shutdown
m_Socket.Shutdown(SocketShutdown.Both);
m_Socket.Close(); // or possibly m_Socket.Disconnect(true);
}
m_bConnected = false;
}

Hard shutdown:
private void Disconnect()
{
if (m_bConnected)
{
// Hard shutdown.
m_Socket.Close();
}
m_bConnected = false;
}

So, using Socket.Close() seems to be a workaround for my issue, however I'd
still like to know how it is possible to bind and connect to a port in a
TIME_WAIT state. The .Net docs seem to suggest its possible with the
ReuseAddress socket option, and the Socket.Disconnect(true) method. Has
anyone gotten this to work successfully?

Thanks.
 
M

Mike Blake-Knox

Rob Gravereaux said:
I have a client Tcp socket that is bound to a particular port and connecting 
to a remote host. In order to allow reconnects I'm setting the ReuseAddress 
socket option. This is somewhat dubious I know, but...

With the ReuseAddress option, a bind to a local port in a TIME_WAIT state 
(netstat -a) does succeed, but the socket connect is failing with the 'Only 
one usage of each socket address...' message. For example, in the following 
code, call Connect(), then Disconnect(), then Connect() again (within the 
TIME_WAIT period, about 4 minutes) and s.Connect(...) throws an exception.

Most TCP clients don't specify a local port and hence don't use the
ReuseAddress socket option. Normally, the client connects to the server with
its hostname and the well known port it's listening on while the client's
operating system (TCP stack) chooses the local port. The server does use the
ReuseAddress option so it can bind to the well-known port immediately after
it's restarted (e.g., after an exception of some kind).

Mike
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top