[ACCEPTED]-How to abort socket's BeginReceive()?-dispose

Accepted answer
Score: 55

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

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

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

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

Score: 2

I am surprised no one recommended using 13 SocketOptions.

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

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

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

For example:

1) Set 4 a small timeout

2) Perform operations

3) Set 3 timeout larger

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

Score: 0

You can read my solution of this problem 2 here(using comment of Pavel Radzivilovsky 1 here): UdpClient.ReceiveAsync correct early termination

Score: 0

For TCP socket connections, you can use 12 the Connected property to determine the state of 11 the socket before trying to access any disposed 10 methods. Per MSDN:

"The Connected property 9 gets the connection state of the Socket 8 as of the last I/O operation. When it returns 7 false, the Socket was either never connected, or 6 is no longer connected."

Since it says 5 "no longer connected" it implies 4 that a Close() was previously called on 3 the socket. If you check whether the socket 2 is Connected at the start of the receive 1 callback, there will be no exception.

Score: 0

In the ReceiveCallback I checked client.Connected 7 within the try block. Now, when data is 6 received after BeginReceive, I can call 5 client.Close(); This way, I do not see exceptions. I 4 send modbus-TCP requests every 200mS, and 3 get responses in time. The console output 2 looks clean. I used a windows forms app, to 1 test this.

    private static void ReceiveCallback(IAsyncResult ar)
    {
        try
        {
            // Retrieve the state object and the client socket
            // from the asynchronous state object.  
            StateObject state = (StateObject)ar.AsyncState;
            Socket client = state.workSocket;
            if (client.Connected)
            {
                // Read data from the remote device.  
                state.dataSize = client.EndReceive(ar);
                if (state.dataSize > 0)
                {
                    Console.WriteLine("Received: " + state.dataSize.ToString() + " bytes from server");
                    // There might be more data, so store the data received so far.  
                    state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, state.dataSize));
                    //  Get the rest of the data.  
                    client.BeginReceive(state.buffer, 0, StateObject.BUFFER_SIZE, 0,
                        new AsyncCallback(ReceiveCallback), state);

                    state.dataSizeReceived = true;           //received data size?

                    dataSize = state.dataSize;
                    buffer = state.buffer.ToArray();
                    dataSizeReceived = state.dataSizeReceived;

                    string hex = ByteArrayToString(state.buffer, state.dataSize);
                    Console.WriteLine("<- " + hex);

                    receiveDone.Set();
                    client.Close();
                }
                else
                {
                    Console.WriteLine("All the data has arrived");
                    // All the data has arrived; put it in response.  
                    if (state.sb.Length > 1)
                    {
                        Console.WriteLine("Length: " + state.sb.Length.ToString());
                    }
                    // Signal that all bytes have been received.  
                    receiveDone.Set();
                }
            }
        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
        }
    }

More Related questions