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

本文关键字:何知道 UdpClient 是否 | 更新日期: 2023-09-27 18:24:54

我通过通常的异步回调从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已经被释放,当我尝试调用EndReceive()时,我得到了一个ObjectDisposedException。我本来以为只是得到一个空的缓冲区。

正确的处理方法是什么?在尝试使用UdpClient之前,我是否可以检查它的某个成员,或者这是将其全部封装在try{}中并捕获ObjectDisposedException的唯一方法?对于正常的收盘来说,这似乎很糟糕。

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

您可以这样做来检查它是否已被处理。当UdpClient被释放时,Client被设置为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;
    }
}

这完全是设计出来的。你做了一些特殊的事情,你关闭了套接字,尽管你希望收到数据。所以你会得到一个例外。.NET框架总是确保异步调用完成,并且在调用EndXxx()时在回调中通知中止原因。好主意,这样可以清理与回调相关的任何状态。

您可以等待传输完成,停止调用BeginReceive()和,然后关闭套接字,从而使其成为非异常。但这并不总是可行的,或者有时你真的想提前终止。没问题,只需捕获ObjectDisposedException并退出即可。当然,确实考虑一下另一端的应用程序会发生什么。它之后发送的任何内容都将落入比特桶,无法发现。

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

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

    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);
    }