Search code examples
c#.net

What is the best way to cancel a socket receive request?


In C# you have 3 ways to try and receive TCP data on a Socket:

  1. Socket.Receive is a synchronous, blocking method. It doesn't return until it succeeds, barring failure or [optionally] timeout.
  2. Socket.BeginReceive is asynchronous, a supplied callback/delegate is called when there is data to receive, using the now-antiquated Begin/End pattern
  3. Socket.ReceiveAsync begins an asynchronous request to receive data

However my understanding is none of these actually let you cancel the receive operation? The docs suggest EndReceive is used for completing a read, not something one could call to terminate the request?

You often see code like while(socket.Available==0 && !cancel)Sleep(50); if(!cancel)socket.Receive(...);

But that's pretty terrible.

If I want to sit waiting for data but at some point cancel the receive, say the user hits "stop" button how can this neatly be done so I don't get a callback triggered later on when unexpected?

I had wondered about closing the socket, which would cause the Receive operation to fail, but it seems somewhat ugly. Am I thinking along the right lines or do the various API methods listed above allow a direct cancellation so I don't risk dangling async operations?


Solution

  • There is no known way to cancel it (AFAIK)

    One thing you can do it set the Socket.Blocking = false. The receive will return immediately when there is no data. This way it will not hang.

    You should check the Socket.Blocking property.

    I advise you to use the BeginReceive(IList<ArraySegment<Byte>>, SocketFlags, SocketError, AsyncCallback, Object) overload to prevent it throwing exceptions.

    Check the SocketError on "Would Block", meaning "there is not data". So you can try again.


    Didn't tested it but ->

    A nice idea is using the non-async version Receive to receive 0 bytes (use a static byte[] emptyBuffer = new byte[0]) , and if the sockerError returns with a 'would block', you can have a short delay and retry it. When it doesn't return a socketError there is probably data. So you can start an async version.