I have this code...
internal static void Start()
{
TcpListener listenerSocket = new TcpListener(IPAddress.Any, 32599);
listenerSocket.Start();
listen
I just ran into this issue myself, and I believe your current solution is incomplete/incorrect. There is no guarantee of atomicity between the check for IsBound and the subsequent call to EndAcceptTcpClient(). You can still get an exception if the listener is Stop()'d between those two statements. You didn't say what exception you're getting but I assume it's the same one I'm getting, ObjectDisposedException (complaining that the underlying socket has already been disposed).
You should be able to check this by simulating the thread scheduling:
IsBound check in your callbackTcpListener.Stop()EndAcceptTcpClient() call. You should see the ObjectDisposedException.IMO the ideal solution would be for Microsoft to throw a different exception from EndAcceptTcpClient in this case, e.g. ListenCanceledException or something like that.
As it is, we have to infer what's happening from the ObjectDisposedException. Just catch the exception and behave accordingly. In my code I silently eat the exception, since I have code elsewhere that's doing the real shutdown work (i.e. the code that called TcpListener.Stop() in the first place). You should already have exception handling in that area anyway, since you can get various SocketExceptions. This is just tacking another catch handler onto that try block.
I admit I'm uncomfortable with this approach since in principle the catch could be a false positive, with a genuine "bad" object access in there. But on the other hand there aren't too many object accesses in the EndAcceptTcpClient() call that could otherwise trigger this exception. I hope.
Here's my code. This is early/prototype stuff, ignore the Console calls.
private void OnAccept(IAsyncResult iar)
{
TcpListener l = (TcpListener) iar.AsyncState;
TcpClient c;
try
{
c = l.EndAcceptTcpClient(iar);
// keep listening
l.BeginAcceptTcpClient(new AsyncCallback(OnAccept), l);
}
catch (SocketException ex)
{
Console.WriteLine("Error accepting TCP connection: {0}", ex.Message);
// unrecoverable
_doneEvent.Set();
return;
}
catch (ObjectDisposedException)
{
// The listener was Stop()'d, disposing the underlying socket and
// triggering the completion of the callback. We're already exiting,
// so just return.
Console.WriteLine("Listen canceled.");
return;
}
// meanwhile...
SslStream s = new SslStream(c.GetStream());
Console.WriteLine("Authenticating...");
s.BeginAuthenticateAsServer(_cert, new AsyncCallback(OnAuthenticate), s);
}