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

时间:2012-02-16 11:23:14

标签: c# asynchronous dispose udpclient

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

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

    //Snip doing stuff with data

    _udpReceive.BeginReceive(OnUdpData, null);
}

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

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

3 个答案:

答案 0 :(得分: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);
}

虽然因为你在一个单独的线程中关闭它,你可能会遇到竞争条件。最好只捕获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;
    }
}

答案 1 :(得分:4)

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

您可以通过等待传输完成来使其成为非例外,停止调用BeginReceive()并然后关闭套接字。但这并不总是实用的,有时你真的想提前终止。没问题,只需捕获ObjectDisposedException并退出即可。当然,会考虑电线另一端的应用程序会发生什么。它之后发送的任何东西都会落入钻头中,无法找到它。

答案 2 :(得分:0)

根据您的问题,这听起来像您想避免在强制客户端关闭时引发异常。我将对您的代码进行一些猜测,并尝试提供一种解决方案:

因为您有一个名为“ OnUdpData”的方法,所以我假设您在UDPClient周围有一个包装器类。在该包装器类中,您可以执行以下操作:设置一个标志,指示您正在关闭客户端,并且在尝试关闭客户端之前 不应再使用该客户端。这样可以避免在调用_udpReceive.Client == null之前检查EndReceive()导致的争用情况,因为主线程可以在进行客户端条件检查后关闭客户端。

    private bool _finishedListening = false;

    public void StopListener()
    {
        _finishedListening = true;
        _udpReceive.Close();
    }

    private void OnUdpData(IAsyncResult result)
    {
      if (_finishedListening == true)
        return;
      byte[] data = _udpReceive.EndReceive(result, ref _receiveEndPoint);
      //Snip doing stuff with data
      _udpReceive.BeginReceive(OnUdpData, null);
    }