How to abort socket's BeginReceive()?

20,374

Solution 1

It seems like this is by (the very dumb) design. You must have this exception thrown and caught in your code.

MSDN looks silent about it indeed, but if you look at the documentation of another asynchronous socket method, BeginConnect(), here's what we find:

To cancel a pending call to the BeginConnect() method, close the Socket. When the Close() method is called while an asynchronous operation is in progress, the callback provided to the BeginConnect() method is called. A subsequent call to the EndConnect(IAsyncResult) method will throw an ObjectDisposedException to indicate that the operation has been cancelled.

If it is the proper way of doing for BeginConnect, it is probably so for BeginReceive as well. This is certainly a poor design on the part of Microsoft's async API, because making the user necessarily throw and catch exception as a part of a normal flow would annoy the debugger. You have really no way to "wait" until the operation is completed, because Close() is what completes it in the first place.

Solution 2

I am surprised no one recommended using SocketOptions.

Once the stack has the send or receive operation it is bound by the socket options of the socket.

Use a small send or receive timeout and use it before the operation so you don't care if it's changed during that same operation to something shorter or longer.

This will cause more context switching but will not require closing the socket under any protocol.

For example:

1) Set a small timeout

2) Perform operations

3) Set timeout larger

This is similar to using Blocking = false but with an automatic timeout that you specify.

Share:
20,374

Related videos on Youtube

Day_Dreamer
Author by

Day_Dreamer

Electrical engineering and Physics student, interested in programming

Updated on August 07, 2021

Comments

  • Day_Dreamer
    Day_Dreamer almost 3 years

    Naturally, BeginReceive() will never end if there's no data. MSDN suggests that calling Close() would abort BeginReceive().

    However, calling Close() on the socket also performs a Dispose() on it, as figured out in this great answer, and consequently EndReceive() would throw an exception because the object is already disposed (and it does!).

    How should I proceed?

  • Kelly
    Kelly about 12 years
    Can't believe it's built to work like this but it is what it is I suppose.
  • supercat
    supercat about 10 years
    @Kelly: What's wrong with it as a design? Code which calls EndReceive will need to handle failures regardless of whether an exception is thrown or not. If the condition can be handled right at the EndReceive, not having it throwing an exception would allow a catch to be replaced with an if, but if it can't be handled then, one would have to add if ( [it failed] ) throw [something] and would still need a catch. Connections shouldn't be aborted often enough for the performance overhead of using an exception vs an if to matter.
  • Pavel Radzivilovsky
    Pavel Radzivilovsky about 10 years
    Because throwing and catching an exception as a part of a normal input, as opposed to an 'exceptional' flow, is a bad design regardless of performance implications. It may also annoy debugging under "break on throw" settings which is often useful.
  • Tom Heard
    Tom Heard almost 10 years
    This doesn't work if he wants to abort AFTER calling BeginReceive. Given BeginReceive creates an Asynchronous callback, it will have that Asynchronous callback waiting until there is data to receive. What if he wants to abort after calling BeginReceive but before the Async callback executes (which is what his question is suggesting)? Your solution wouldn't work in this case.
  • Tom Heard
    Tom Heard almost 10 years
    Therefore Exception handling is needed in the OP's case, as the only way to Abort the asynchronous callback is to close the socket. Which will cause an ObjectDisposedException to be thrown on EndReceive.
  • Jay
    Jay over 9 years
    a lot of things are dumb in .Net, StreamReader, BinaryReader, (leaveOpen, DiscardBufferedData...) The ASync and Begin methods really just wrap the logic of Send and Receive in most anyway so in this case as most others the synchronous operation has to be cancel-able to support such a concept.
  • Jay
    Jay over 9 years
    They could also use a wait handle or event. They could also could use options as I indicated in my answer. This requires another socket per client and server.
  • Michael Wojcik
    Michael Wojcik almost 7 years
    The socket send/receive timeout options only apply while a blocking I/O operation is in progress. I haven't looked at how the Framework's async I/O is implemented, but I'm hoping it's with an actual async mechanism such as WSASelect or I/O completion ports, and not some thread sitting in a blocking operation.
  • Christopher Pisz
    Christopher Pisz over 6 years
    You realize these async sockets are within a multithreaded program right? You can check on one line in thread A and the execution then can close in thread B, then back in thread A your condition is out the window.