Handle leak in Socket.BeginConnect()

  • Thread starter Thread starter Bryan Mayland
  • Start date Start date
B

Bryan Mayland

I've got a problem with a System.Net.Socket that is failing on
connect. Each time I attempt a connection, 3 handles are allocated,
and when the connect fails 2 handles are freed. If left retrying over
a long period of time the extra handles build up to several thousand
quite quickly. Here's the C# code:
private void StartConnect()
{
// Allocate 1 handle for socket
Socket y = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);

IPHostEntry he = Dns.Resolve(_host);
if (he.AddressList.Length == 0)
throw new Exception("Could not resolve host " +
_host);

IPEndPoint hostEndPoint = new
IPEndPoint(he.AddressList[0], _port);
// Allocate 1 handle for asyncwait
// Allocate another handle for ???
y.BeginConnect(hostEndPoint, new
AsyncCallback(AsyncConnectComplete), y);
y = null;
}

private void AsyncConnectComplete(IAsyncResult ar)
{
Socket s = (Socket)ar.AsyncState;
try
{
// Throws exception because connect failed
s.EndConnect(ar);
}
catch (SocketException e)
{
// Free socket handle
// Free asyncwait handle
s.Close();
s = null;
}
}

Each call to StartConnect and its subsequent failure leaves one handle
open. The handle can be recovered by forcing a garbage collection
with GC.Collect().

Is there something I'm missing here? Calling GC.Collect() all the
time is a terrible solution to this problem.
 
Bryan,

The problem comes from the fact that you are never closing the socket if
the connection succeeds. The variable y holds the socket in the
StartConnect method, and goes out of scope. However, you have passed it
along as the AsyncState for the asynchronous operation.

Then, in the AsyncConnectComplete method, you only call Close if there
is an error. You should place the call to Close (or Dispose) in a finally
clause, so that it is always disposed of. You only try and call EndConnect,
and that does not dispose of the socket.

Hope this helps.
 
Actually I should have specified. In the short test code I posted
I've removed the extra code. I know that you're supposed to actually
do something with the socket once it connected. The test code is
supposed to never actually get a connection, since I have no problems
if the socket actually connects.

If it does connect, then yes it will leak, but for testing purposes
you have to make sure the connect fails ever time.
 
Back
Top