您如何“取消” UdpClient::BeginReceive?
Posted
技术标签:
【中文标题】您如何“取消” UdpClient::BeginReceive?【英文标题】:How do you 'cancel' a UdpClient::BeginReceive? 【发布时间】:2013-08-21 00:34:35 【问题描述】:我有一个线程等待来自多个接口的 UDP 消息,使用 UdpClient::BeginReceive
和一个调用 UdpClient::EndReceive
的回调来获取数据并将其传递。
如果 5 秒后我什么也没得到,我会从调用 UdpClient::BeginReceive
的函数返回,以便可以取消进程并发出另一个广播,这将触发外部客户端发送 UDP 响应。如果我们不取消,我会再次调用UdpClient::BeginReceive
函数来检查新数据。
如果客户端没有及时收到任何数据,有没有办法取消该异步请求而无需调用无限期阻塞的EndReceive
?我的印象是让数百个异步触发器运行是个坏主意。
【问题讨论】:
【参考方案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。请添加更多信息此代码的作用以及解决问题的原因。以上是关于您如何“取消” UdpClient::BeginReceive?的主要内容,如果未能解决你的问题,请参考以下文章