我想使用VB.Net在UDP多播接收器中实现超时。基本上,如果我在10秒内没有收到任何数据包,我想停止侦听。我可以很容易地使用间隔为10000的Timer
来知道何时需要超时,但问题是如何停止接收功能?如果我使用Receive()
函数(阻止它的函数),我可以简单地通过Thread.Abort()
调用来停止它。然而,我所读到的一切都表明,这不是一种安全的做法。如果我使用异步BeginReceive()
函数,我不知道如何在它正常完成之前终止它,因为如果不使用从BeginReceive()
返回的IASyncResult
调用EndReceive()
,CCD_5将抛出异常。
这个问题的答案使我开始研究CancelAsync()
方法。但是,这个问题的答案让我很紧张。
如果我使用阻塞接收,我将无法连续轮询CancellationPending
属性,除非我在DoWork处理程序中的Receive()
自己的线程中调用它。但这意味着它将在取消生效后继续运行,对吗?如果我使用BeginReceive()
,我担心CancelAsync()
会被DoWork处理程序"吃掉",我最终会遇到同样的问题。
此外,BackgroundWorker
文档中的这个片段也不太令人放心。。。
请注意,DoWork事件处理程序中的代码可能会在发出取消请求时完成其工作,并且您的轮询循环可能会错过CancellationPending设置为true。在这种情况下,系统的Cancelled标志。组件模型。即使发出了取消请求,RunWorkerCompleted事件处理程序中的RunWorkerCompletedEventArgs也不会设置为true。
我想到的一个替代方案是让发送数据包的UdpClient
负责超时,然后让它发送某种取消信号数据包,以指示接收器应该停止侦听。这样做的问题是,考虑到UDP的性质,不能保证所述数据包会到达,或者以正确的顺序被拾取。
有没有一种方法可以在UDP接收过程结束之前安全地终止它?
我在UdpClient中遇到了同样的问题,我不确定安全的解决方案是什么/是否存在"安全"的解决方案。然而,我遇到了一个用户为另一个问题发布的函数,该函数跟踪并终止超过特定时间跨度的代码块,我只是将对UdpClient.rereceive()的调用封装在其中。如果你想尝试一下,该函数看起来像这样:
private static bool TrackFunction(TimeSpan timeSpan, Action codeBlock)
{
try
{
Task task = Task.Factory.StartNew(() => codeBlock());
task.Wait(timeSpan);
return task.IsCompleted;
}
catch (AggregateException ae)
{
throw ae.InnerExceptions[0];
}
}
你可以简单地将它包装在你的代码中,就像这样:
bool timeTracker = TrackFunction(TimeSpan.FromSeconds(10), () =>
{
Byte[] received = myUdpClient.Receive(ref myIPEndPoint);
}
同样,可能有更好的解决方案,但这正是我所使用的。
我遇到过类似的情况,我打开了与远程设备的几个连接(Udp、Serial等),并需要在它们之间切换;听众";使用阻塞CCD_ 15调用的线程。调用Thread.Abort()
导致崩溃,在不首先退出线程的情况下切换连接实例(UdpClient)也不起作用,因为线程挂在UdpClient.Receive()
上,while循环中的一个简单标志从未退出。
最终起作用的是关闭主应用程序线程中的连接,这将导致UdpClient.Receive()
抛出一个可以捕获和处理的异常。应用程序创建代表各种连接的CCD_ 19的实例;听众";可以通过设置全局标志并关闭当前CCD_ 20实例来终止的线程。我使用了VB.NET,它看起来像这样:
Dim mListening as Boolean 'application flag for exiting Listener thread
Dim mReceiver as UdpClient 'a connection instance
...
Private Sub Listener()
While mListening
Try
Dim reply = mReceiver.Receive()
Catch ex As Exception
'execution goes here when mReceiver.Close() called
End Try
End While
End Sub
应用程序设置mListening
并启动Listener线程。当应用程序需要";解锁";则它调用mReceiver.Close()
并相应地处理它。我毫无问题地使用了这个方案。我正在使用VS 2019和。NET v4.7