【问题标题】:How do you 'cancel' a UdpClient::BeginReceive?您如何“取消” UdpClient::BeginReceive?
【发布时间】:2013-08-21 00:34:35
【问题描述】:

我有一个线程等待来自多个接口的 UDP 消息,使用 UdpClient::BeginReceive 和一个调用 UdpClient::EndReceive 的回调来获取数据并将其传递。

如果 5 秒后我什么也没得到,我会从调用 UdpClient::BeginReceive 的函数返回,以便可以取消进程并发出另一个广播,这将触发外部客户端发送 UDP 响应。如果我们不取消,我会再次调用UdpClient::BeginReceive 函数来检查新数据。

如果客户端没有及时收到任何数据,有没有办法取消该异步请求而无需调用无限期阻塞的EndReceive?我的印象是让数百个异步触发器运行是个坏主意。

【问题讨论】:

    标签: .net asynchronous c++-cli udpclient


    【解决方案1】:

    您需要猛拉地垫,调用 UdpClient.Close() 方法。

    这将完成 BeginReceive() 调用并且您的回调方法将运行。当您调用 EndReceive() 时,该类会告知您地垫已消失,并将引发 ObjectDisposedException。所以准备好处理这个异常,用 try/catch 包装 EndReceive() 调用,这样你就可以捕获 ODE 并退出回调方法。

    请注意,这往往会让 .NET 程序员有些不安,通常强烈建议不要使用异常进行流控制。但是,您必须调用 EndInvoke(),即使您已经知道这会引发异常。否则会导致资源泄漏,可能会持续一段时间。

    【讨论】:

    • 这几乎是我发布问题后得出的结论。我的实现现在不是最干净的。真的,我认为我应该让每个接口运行一个侦听器,并且只使用 Close() 关闭,正如您在需要正确处理事情时所建议的那样。感谢您的确认。
    【解决方案2】:

    对于取消BeginRecieve,您可以使用Close 方法,但在基本实现中它将调用ObjectDisposedException。我通过创建自定义 BeginRecieve 来修复它,这是基础实现的现代化:

    public Task<UdpReceiveResult> ReceiveAsync(UdpClient client, CancellationToken breakToken)
        => breakToken.IsCancellationRequested
            ? Task<UdpReceiveResult>.Run(() => new UdpReceiveResult())
            : Task<UdpReceiveResult>.Factory.FromAsync(
                (callback, state) => client.BeginReceive(callback, state),
                (ar) =>
                    {
                        if (breakToken.IsCancellationRequested)
                            return new UdpReceiveResult();
    
                        IPEndPoint remoteEP = null;
                        var buffer = client.EndReceive(ar, ref remoteEP);
                        return new UdpReceiveResult(buffer, remoteEP);
                    },
                null);
    

    阅读更多:UdpClient.ReceiveAsync correct early termination

    这也会有所帮助:Is it safe to call BeginXXX without calling EndXXX if the instance is already disposed

    【讨论】:

      【解决方案3】:
            // Set ReadMsg = true while using UdpClient
            // Set ReagMsg = false before Dispose or Close no Exception Error
            private static bool ReadMsg;
            private static void ReceiveCallback(IAsyncResult ar)
            {
      
              UdpClient u = (UdpClient)((UdpState)(ar.AsyncState)).u;
              IPEndPoint e = (IPEndPoint)((UdpState)(ar.AsyncState)).e;
              try
              {
                  if ( ReadMsg )
                  {
                      Byte[] receiveBytes = u.EndReceive(ar, ref e);
                      string sddpMessage = Encoding.ASCII.GetString(receiveBytes);
      
                  }
              }
              catch (Exception ex)
              {
                  Debug.WriteLine($"{ex.Message}");
              }
          }
      

      【讨论】:

      • 欢迎来到 SO。请添加更多信息此代码的作用以及解决问题的原因。
      猜你喜欢
      • 1970-01-01
      • 2012-12-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-03-07
      • 2011-08-29
      • 2011-03-28
      相关资源
      最近更新 更多