我如何知道UdpClient是否已被关闭/处置?

Gaz*_*yer 4 c# dispose asynchronous udpclient

我通过常见的异步回调从UdpClient接收数据:

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

    //Snip doing stuff with data

    _udpReceive.BeginReceive(OnUdpData, null);
}
Run Code Online (Sandbox Code Playgroud)

当我Close()在主线程中的UdpClient时,回调会像我期望的那样触发,但是此时_udpReceive已经处理掉了,ObjectDisposedException当我尝试呼叫时我得到了一个EndReceive().我本来希望得到一个空的缓冲区.

处理这个问题的正确方法是什么?UdpClient在尝试使用它之前是否有一些我可以检查的成员,或者它是唯一的方法将它包装在一起try{}并捕获ObjectDisposedException?对于正常的关闭来说,这看起来非常糟糕.

Wil*_*ill 5

你可以这样做,以检查它是否处置.处理UdpClient时,客户端设置为null.

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);
}
Run Code Online (Sandbox Code Playgroud)

虽然因为你在一个单独的线程中关闭它,你可能会遇到竞争条件.最好只捕获ObjectDisposedException和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;
    }
}
Run Code Online (Sandbox Code Playgroud)


Han*_*ant 4

这完全是设计使然。您做了一些特殊的事情,即使您希望收到数据,也关闭了套接字。所以你会得到一个例外。.NET 框架始终确保异步调用完成,并且在调用 EndXxx() 时在回调中发出中止原因信号。好主意,它可以让您清理与回调相关的任何状态。

您可以通过等待传输完成、停止调用 BeginReceive() 然后关闭套接字使其正常。但这并不总是可行,或者有时您确实想提前终止。没问题,只需捕获 ObjectDisposeException 并退出即可。当然,请务必考虑线路另一端的应用程序会发生什么情况。之后发送的任何内容都会落入比特桶中,而无法找到。