Results 1 to 5 of 5

Thread: [RESOLVED] Closing a TcpListener without getting WSACancelBlockingCall exception

  1. #1

    Thread Starter
    Pro Grammar chris128's Avatar
    Join Date
    Jun 2007
    Location
    England
    Posts
    7,604

    Resolved [RESOLVED] Closing a TcpListener without getting WSACancelBlockingCall exception

    I have a background thread that sits waiting for new clients to connect to my TcpListener and when a new client connects it passes it off onto another worker thread and then loops straight back to waiting for another client. Like so:

    vb.net Code:
    1. Do While DoListen
    2.      Threading.ThreadPool.QueueUserWorkItem(AddressOf ManageSession, SMTPListener.AcceptTcpClient())
    3. Loop

    Thats all fine but I want to be able to cancel this 'listening' activity, which I cannot do as AcceptTcpClient is a blocking method. So when I call Stop() on the TcpClient instance I get the following exception:
    A blocking operation was interrupted by a call to WSACancelBlockingCall
    Obviously I could just handle the exception and ignore it but I'm sure there must be a more proper way of doing it. One thing I am thinking of trying is using the BeginAcceptTcpClient and EndAcceptTcpClient methods but for one thing I'm not sure if that will actually help and for another thing the Begin and End versions of methods have always confused me in the past... I mean for a start how do you know when to call End?

    Anyway, I figured this must be a fairly common problem but searching the forum only turned up one result and it wasnt any use. I'll keep playing around and trawling google but just wondered if anyone had come across this before?
    My free .NET Windows API library (Version 2.2 Released 12/06/2011)

    Blog: cjwdev.wordpress.com
    Web: www.cjwdev.co.uk


  2. #2
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    111,221

    Re: Closing a TcpListener without getting WSACancelBlockingCall exception

    Quote Originally Posted by chris128 View Post
    One thing I am thinking of trying is using the BeginAcceptTcpClient and EndAcceptTcpClient methods but for one thing I'm not sure if that will actually help and for another thing the Begin and End versions of methods have always confused me in the past... I mean for a start how do you know when to call End?
    This is presumably why you didn't really take to my suggestion of calling BeginRead in another of your threads.

    Calling BeginAcceptTcpClient will presumably solve your problem because your problem is specifically that you're interrupting a blocking call, while asynchronous methods are inherently non-blocking.

    The asynchronous model is not all that complicated. When using synchronous methods you call the method and then you use the result when it returns. When using asynchronous methods you call the method and specify a callback, i.e. a method you want invoked when an asynchronous result is available. In that method you call the appropriate End method and then you use the result. The End method returns what the corresponding synchronous method would have returned. For instance, using the synchronous model you might do this:
    vb.net Code:
    1. Private Sub Listen()
    2.     Dim server As New TcpListener(IPAddress.Parse("127.0.0.1"), 12345)
    3.  
    4.     server.Start()
    5.  
    6.     Dim client = server.AcceptTcpClient()
    7.  
    8.     'Use client here.
    9. End Sub
    while the asynchronous equivalent would be:
    vb.net Code:
    1. Private Sub Listen()
    2.     Dim server As New TcpListener(IPAddress.Parse("127.0.0.1"), 12345)
    3.  
    4.     server.Start()
    5.     server.BeginAcceptTcpClient(AddressOf Accept, server)
    6. End Sub
    7.  
    8. Private Sub Accept(ByVal ar As IAsyncResult)
    9.     Dim server = DirectCast(ar.AsyncState, TcpListener)
    10.     Dim client = server.EndAcceptTcpClient(ar)
    11.  
    12.     'Use client here.
    13. End Sub
    It's important to note that the callback is invoked on a thread pool thread, NOT the thread on which you called the Begin method.
    Last edited by jmcilhinney; Aug 17th, 2009 at 09:04 PM.
    Why is my data not saved to my database? | MSDN Data Walkthroughs
    VBForums Database Development FAQ
    My CodeBank Submissions: VB | C#
    My Blog: Data Among Multiple Forms (3 parts)
    Beginner Tutorials: VB | C# | SQL

  3. #3

    Thread Starter
    Pro Grammar chris128's Avatar
    Join Date
    Jun 2007
    Location
    England
    Posts
    7,604

    Re: Closing a TcpListener without getting WSACancelBlockingCall exception

    Ah I see, well that doesnt seem very difficult at all I had tried before using the MSDN documentation and failed miserably. Will definitely try that tonight though and let you know how it goes

    Oh and no its not why I didnt take to your suggestion about the BeginRead method I just thought you had not quite understood what the problem was with my loop in the other thread.
    My free .NET Windows API library (Version 2.2 Released 12/06/2011)

    Blog: cjwdev.wordpress.com
    Web: www.cjwdev.co.uk


  4. #4

    Thread Starter
    Pro Grammar chris128's Avatar
    Join Date
    Jun 2007
    Location
    England
    Posts
    7,604

    Re: Closing a TcpListener without getting WSACancelBlockingCall exception

    OK so I've got the Async version working but with one big problem - it can only run once. With the blocking method obviously I could just do an infinite loop that kept calling the blocking AcceptTcpClient method because it would only loop round when a new client connects. With this BeginAcceptTcpClient method though it just passes straight over that line obviously, so I didnt put it in a loop for obvious reasons.

    In the MSDN documentation they use something I've not come across before: a ManualResetEvent.
    vb.net Code:
    1. ' Thread signal.
    2. Public Shared tcpClientConnected As New ManualResetEvent(False)
    Then when a connection is accepted they call the WaitOne method and then in the callback after they have called EndAcceptTcpClient they reset the ManualResetEvent so that the original thread can continue. So I figure I can just do the same thing but in a loop but is this the standard practice for something like this? I'm just surprised I've never seen anyone mention this class before


    EDIT: I have this working the way I want now using the ManualResetEvent but would still be grateful if someone could just confirm whether or not this is a pretty normal way of dealing with this situation here is my current code:
    vb.net Code:
    1. 'At class level
    2. Private ThreadWaitSignal As New System.Threading.ManualResetEvent(False)

    vb.net Code:
    1. 'In a method that runs on a background thread
    2. Do While DoListen
    3.             ThreadWaitSignal.Reset()
    4.             SMTPListener.BeginAcceptTcpClient(AddressOf IncomingConnection, SMTPListener)
    5.             ThreadWaitSignal.WaitOne()
    6. Loop

    vb.net Code:
    1. 'The method that the BeginAcceptTcpClient calls back to when complete
    2.    Private Sub IncomingConnection(ByVal ar As IAsyncResult)
    3.         Try
    4.             Dim Client = DirectCast(ar.AsyncState, TcpListener).EndAcceptTcpClient(ar)
    5.             Threading.ThreadPool.QueueUserWorkItem(AddressOf ManageSession, Client)
    6.             ThreadWaitSignal.Set()
    7.         Catch disposedEx As ObjectDisposedException
    8.             Debug.WriteLine(disposedEx.Message)
    9.         End Try
    10.     End Sub
    Oh and if anyone has any ideas how to avoid having to catch that ObjectDisposedException that would be good but google seems to suggest that is all you can do (when you call Stop on the TcpListener then that exception is thrown in the callback)
    Last edited by chris128; Aug 18th, 2009 at 02:48 PM.
    My free .NET Windows API library (Version 2.2 Released 12/06/2011)

    Blog: cjwdev.wordpress.com
    Web: www.cjwdev.co.uk


  5. #5

    Thread Starter
    Pro Grammar chris128's Avatar
    Join Date
    Jun 2007
    Location
    England
    Posts
    7,604

    Re: Closing a TcpListener without getting WSACancelBlockingCall exception

    Any thoughts/comments on whether or not using this ManualResetEvent thingy is the best way to go about this?
    My free .NET Windows API library (Version 2.2 Released 12/06/2011)

    Blog: cjwdev.wordpress.com
    Web: www.cjwdev.co.uk


Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width