Closing a C# socket does not release port

O

O.B.

I have a socket configured as TCP and running as a listener. When I
close socket, it doesn't always free up the port immediately. Even
when no connections have been made to it. So when I open the socket
again, the bind fails because the port is still in use. When I
execute the code in "debug" mode, the problem never occurs. When I
execute the same code in release mode, the problem appears about 20%
of the time.

Here's the code:

protected Socket socket = null;

public void Open()
{
socket = new Socket(AddressFamily.InterNetwork,
SocketType.Stream,
ProtocolType.Tcp);

socket.SetSocketOption(SocketOptionLevel.Socket,
SocketOptionName.DontLinger,
true);

IPEndPoint endPoint = new IPEndPoint(
System.Net.IPAddress.Parse(socketConfig.Address),
socketConfig.Port);

socket.Bind(endPoint);
socket.Listen(MAX_NUM_CONNECTIONS);

serverConnectThread = new Thread(ServerConnectThread);
serverConnectThread.Start();
}

public void Close()
{
socket.Close();
socket = null;
}

protected virtual void ServerConnectThread()
{
IAsyncResult result;
while (true)
{
if (socket != null && socket.IsBound)
{
try
{
result = socket.BeginAccept(new
AsyncCallback(ServerAcceptConnection), socket);
}
catch (Exception exception)
{
Close();
break;
}
}
else
{
break;
}
// Wait for the EndAccept before issuing a new BeginAccept
result.AsyncWaitHandle.WaitOne();
}
}
 
N

Nicholas Paldino [.NET/C# MVP]

I don't see anything that is odd about how you are opening and closing
the socket (although what you are doing with the Socket that is returned
from the call to EndAccept isn't shown, I'm sure you call Close on that, but
that shouldn't affect the main socket anyways).

What I am curious about is why you are calling BeginAccept in the first
place. You are waiting on an event in the thread which I am sure you are
setting after you perform the callback where you call EndAccept. Why not
just call Accept in your thread, do your work and be done with it?

Also, are you making calls to Open from multiple threads? If you are,
then I imagine that you could have a race condition where you are creating a
new socket without closing the old one, and since the old socket is still
bound to the port, getting the exception.
 
O

O.B.

Only one thread is calling the Open operation.

I'm using BeginAccept because it starts a new thread when a connection
is made. The operation specified within BeginAccept goes into a loop
of receiving data from the socket. Granted, I could use "Accept"
instead and create a new thread myself each time. Unless I'm
mistaken, the two approaches do the exact same thing.

In one of my test cases, the socket is opened, closed, and
dereference. The test sleeps 2 seconds and repeats the cycle two more
times. A connection is never made to the socket. In 20% of the
executions, I encounter a socket exception when trying to open the
socket because the port is still in use.




I don't see anything that is odd about how you are opening and closing
the socket (although what you are doing with the Socket that is returned
from the call to EndAccept isn't shown, I'm sure you call Close on that, but
that shouldn't affect the main socket anyways).

What I am curious about is why you are calling BeginAccept in the first
place. You are waiting on an event in the thread which I am sure you are
setting after you perform the callback where you call EndAccept. Why not
just call Accept in your thread, do your work and be done with it?

Also, are you making calls to Open from multiple threads? If you are,
then I imagine that you could have a race condition where you are creating a
new socket without closing the old one, and since the old socket is still
bound to the port, getting the exception.

--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)


I have a socket configured as TCP and running as a listener. When I
close socket, it doesn't always free up the port immediately. Even
when no connections have been made to it. So when I open the socket
again, the bind fails because the port is still in use. When I
execute the code in "debug" mode, the problem never occurs. When I
execute the same code in release mode, the problem appears about 20%
of the time.
Here's the code:
protected Socket socket = null;
public void Open()
{
socket = new Socket(AddressFamily.InterNetwork,
SocketType.Stream,
ProtocolType.Tcp);

IPEndPoint endPoint = new IPEndPoint(
System.Net.IPAddress.Parse(socketConfig.Address),
socketConfig.Port);

serverConnectThread = new Thread(ServerConnectThread);
serverConnectThread.Start();
}
public void Close()
{
socket.Close();
socket = null;
}
protected virtual void ServerConnectThread()
{
IAsyncResult result;
while (true)
{
if (socket != null && socket.IsBound)
{
try
{
result = socket.BeginAccept(new
AsyncCallback(ServerAcceptConnection), socket);
}
catch (Exception exception)
{
Close();
break;
}
}
else
{
break;
}
// Wait for the EndAccept before issuing a new BeginAccept
result.AsyncWaitHandle.WaitOne();
}
}
 
P

Peter Duniho

I don't see anything that is odd about how you are opening and
closing the socket (although what you are doing with the Socket that is
returned from the call to EndAccept isn't shown, I'm sure you call
Close on that, but that shouldn't affect the main socket anyways).

What I am curious about is why you are calling BeginAccept in the
first place. You are waiting on an event in the thread which I am sure
you are setting after you perform the callback where you call
EndAccept. Why not just call Accept in your thread, do your work and
be done with it?

Agreed. Or alternatively, forget the loop in ServerConnectThread()
(and for that matter, probably forget the "server connect thread"
altogether) and just call BeginAccept() again from within the EndAccept
callback method. This is a more typical use of the async methods.
Also, are you making calls to Open from multiple threads? If you
are, then I imagine that you could have a race condition where you are
creating a new socket without closing the old one, and since the old
socket is still bound to the port, getting the exception.

In addition, be aware that a listening socket simply is not normally
removed right away when closed. See "TIME_WAIT" for more details.
Even in perfectly working code, with or without .NET, it's not uncommon
to have to wait some period of time before you can bind a new socket to
a previously used address.

See SocketOptionName.ReuseAddress for a workaround.

Pete
 
P

Peter Duniho

Only one thread is calling the Open operation.

I'm using BeginAccept because it starts a new thread when a connection
is made. The operation specified within BeginAccept goes into a loop
of receiving data from the socket. Granted, I could use "Accept"
instead and create a new thread myself each time. Unless I'm
mistaken, the two approaches do the exact same thing.

Ouch. Don't do that. At the very least, you'll run out of thread pool
threads. It's possible that you'll screw up the async implementation
of the Socket class as well. Make sure that in your callback, you
process the completed operation without delay and return immediately.

If you want to use the async methods, use them correctly. That means
don't create your own threads for the socket. Let the async methods
use the IOCP thread pool as it was designed. In the completion
callback for the various methods (i.e. the methods where you call
EndAccept, EndRecieve, etc.), simply call the "Begin..." method again
to allow a new network operation to occur. After calling EndAccept,
call BeginAccept. After calling EndReceive, call BeginReceive. And so
forth.

If you want to create your own threads for the socket operations, then
don't use the async methods.

Pete
 

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