Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>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 <code>IsBound</code> and the subsequent call to <code>EndAcceptTcpClient()</code>. You can still get an exception if the listener is <code>Stop()</code>'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, <code>ObjectDisposedException</code> (complaining that the underlying socket has already been disposed).</p> <p>You should be able to check this by simulating the thread scheduling:</p> <ul> <li>Set a breakpoint on the line after the <code>IsBound</code> check in your callback</li> <li>Freeze the thread that hits the breakpoint (Threads window -> right click, "Freeze")</li> <li>Run/trigger the code that calls <code>TcpListener.Stop()</code></li> <li>Break in and step through the <code>EndAcceptTcpClient()</code> call. You should see the <code>ObjectDisposedException</code>.</li> </ul> <p>IMO the ideal solution would be for Microsoft to throw a different exception from <code>EndAcceptTcpClient</code> in this case, e.g. <code>ListenCanceledException</code> or something like that.</p> <p>As it is, we have to infer what's happening from the <code>ObjectDisposedException</code>. 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 <code>TcpListener.Stop()</code> in the first place). You should already have exception handling in that area anyway, since you can get various <code>SocketExceptions</code>. This is just tacking another catch handler onto that try block.</p> <p>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 <code>EndAcceptTcpClient()</code> call that could otherwise trigger this exception. I hope.</p> <p>Here's my code. This is early/prototype stuff, ignore the Console calls.</p> <pre><code> 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); } </code></pre>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload