How do I know if UdpClient has been closed/disposed?

GazTheDestroyer picture GazTheDestroyer · Feb 16, 2012 · Viewed 8.1k times · Source

I am receiving data from UdpClient via the usual async callback:

private void OnUdpData(IAsyncResult result)
{
    byte[] data = _udpReceive.EndReceive(result, ref _receiveEndPoint);

    //Snip doing stuff with data

    _udpReceive.BeginReceive(OnUdpData, null);
}

When I Close() the UdpClient in the main thread, the callback fires as I would expect, but at this point _udpReceive is already disposed and I get an ObjectDisposedException when I try and call EndReceive(). I was expecting to just get an empty buffer.

What is the correct way to handle this? Is there some member of UdpClient I can check before trying to use it, or it the only way to wrap it all in a try{} and catch the ObjectDisposedException? That seems pretty nasty for a normal close.

Answer

Will picture Will · Feb 16, 2012

You can do this to check if its disposed. Client is set to null when the UdpClient is disposed.

private void OnUdpData(IAsyncResult result)
{
    if (_udpReceive.Client == null)
        return;
    byte[] data = _udpReceive.EndReceive(result, ref _receiveEndPoint);

    //Snip doing stuff with data

    if (_udpReceive.Client == null)
        return;
    _udpReceive.BeginReceive(OnUdpData, null);
}

Although because you are closing it in a separate thread you may end up with a race condition. It would be best to just catch ObjectDisposedException and SocketException.

private void OnUdpData(IAsyncResult result)
{
    try
    {
        byte[] data = _udpReceive.EndReceive(result, ref _receiveEndPoint);

        //Snip doing stuff with data

        _udpReceive.BeginReceive(OnUdpData, null);
    }
    catch (Exception e)
    {
        //You may also get a SocketException if you close it in a separate thread.
        if (e is ObjectDisposedException || e is SocketException)
        {
            //Log it as a trace here
            return;
        }
        //Wasn't an exception we were looking for so rethrow it.
        throw;
    }
}