I wrote a simple test program, using two different techniques for accomplishing your goal, as well as also testing the exact code you posted. I was unable to reproduce the problem you are describing. Whether I use TcpClient
or Socket
directly, calling Close()
on the object results in the connection operation completing immediately (well, in less than 1/10th of a second, after all the async completion, exception handling, thread synchronization, etc.)
Do note that in the TcpClient
case, the TcpClient
class seems to have a bug in that it throws NullReferenceException
instead of (as one would expect) ObjectDisposedException
. This appears to be because TcpClient
sets the Client
property to null
when Close()
is called, but then tries to use that value when invoking the completion delegate. Oops.
That means that in your code, the caller would see NullReferenceException
instead of the Exception
you seem to want to throw. But that doesn't seem like it would cause an actual delay per se.
Here is my test program:
class Program
{
static void Main(string[] args)
{
_TestWithSocket();
_TestWithTcpClient();
try
{
_TestSOCode();
}
catch (Exception e)
{
Console.WriteLine("Exception: " + e);
}
}
private static void _TestSOCode()
{
using (var tcp = new TcpClient())
{
var c = tcp.BeginConnect(IPAddress.Parse("8.8.8.8"), 8080, null, null);
var success = c.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(1));
if (!success)
{
Console.WriteLine("Before cleanup");
tcp.Close();
tcp.EndConnect(c);
Console.WriteLine("After cleanup");
throw new Exception("Failed to connect.");
}
}
}
private static void _TestWithTcpClient()
{
TcpClient client = new TcpClient();
object o = new object();
Console.WriteLine("connecting TcpClient...");
client.BeginConnect("8.8.8.8", 8080, asyncResult =>
{
Console.WriteLine("connect completed");
try
{
client.EndConnect(asyncResult);
Console.WriteLine("client connected");
}
catch (NullReferenceException)
{
Console.WriteLine("client closed before connected: NullReferenceException");
}
catch (ObjectDisposedException)
{
Console.WriteLine("client closed before connected: ObjectDisposedException");
}
lock (o) Monitor.Pulse(o);
}, null);
Thread.Sleep(1000);
Stopwatch sw = Stopwatch.StartNew();
client.Close();
lock (o) Monitor.Wait(o);
Console.WriteLine("close took {0:0.00} seconds", sw.Elapsed.TotalSeconds);
Console.WriteLine();
}
private static void _TestWithSocket()
{
Socket socket = new Socket(SocketType.Stream, ProtocolType.Tcp);
object o = new object();
Console.WriteLine("connecting Socket...");
socket.BeginConnect("8.8.8.8", 8080, asyncResult =>
{
Console.WriteLine("connect completed");
try
{
socket.EndConnect(asyncResult);
Console.WriteLine("socket connected");
}
catch (ObjectDisposedException)
{
Console.WriteLine("socket closed before connected");
}
lock (o) Monitor.Pulse(o);
}, null);
Thread.Sleep(1000);
Stopwatch sw = Stopwatch.StartNew();
socket.Close();
lock (o) Monitor.Wait(o);
Console.WriteLine("close took {0:0.00} seconds", sw.Elapsed.TotalSeconds);
Console.WriteLine();
}
}
Unfortunately, you have not provided an actual complete code example demonstrating the problem. If in your environment the above code demonstrates the problem you describe then, since it doesn't do so in my environment, that obviously means there's something about your environment causing the problem. Different OS version, different .NET version, etc.
In that case, you should be specific about the particular aspect of your environment that might be relevant.
If the above code example works as desired, and does not demonstrate the problem you describe, then you simply need to figure out what is in the code you have that is different and causing the problem. In that case, if you still can't actually figure out the problem, you should post a minimal, complete code example that demonstrates the problem.