我可以在C#中设置UdpClient的超时时间吗?

43

我想知道是否可以为UdpClient的接收方法设置超时值。

我想使用阻塞模式,但因为有时候udp会丢失数据包,我的程序中udpClient.receive方法会一直挂在那里。

你有什么好的方法来解决这个问题吗?

5个回答

67

UdpClientSocket中有一个SendTimeoutReceiveTimeout属性可供使用。

以下是5秒超时的示例:

var udpClient = new UdpClient();

udpClient.Client.SendTimeout = 5000;
udpClient.Client.ReceiveTimeout = 5000;

...

7
仅在同步发送/接收时才起作用。对于异步调用,您可以使用 Task.Delay 创建自己的超时,例如 Task.WhenAny(udpClient.ReceiveAsync(), Task.Delay(5000)) - AJ Richardson
当然了!我怎么会错过这么简单的解决方案呢!感谢你的评论,AJ! - Jörgen Sigvardsson
@AJRichardson 嗯,我认为这不是一个好的方法,因为当计时器-ask完成进程后,udpClient.ReceiveAsync()仍然会处于等待状态... 我建议可能使用以下方式:Task.WaitAny(new[] { udpClient.ReceiveAsync() }, waitTimeOutInMs); - Ivandro Jao
1
@IvandroJao 你说得对,虽然我不知道你的代码能否解决这个问题。听起来像是在超时情况下应该关闭socket:请参阅https://dev59.com/qGjWa4cB1Zd3GeqPv_k3#12642359 - AJ Richardson

37

菲利普所指的是嵌套在UdpClient中的套接字(UdpClient.Client.ReceiveTimeout)。

您也可以使用异步方法来完成此操作,但需要手动阻止执行:

var timeToWait = TimeSpan.FromSeconds(10);

var udpClient = new UdpClient( portNumber );
var asyncResult = udpClient.BeginReceive( null, null );
asyncResult.AsyncWaitHandle.WaitOne( timeToWait );
if (asyncResult.IsCompleted)
{
    try
    {
        IPEndPoint remoteEP = null;
        byte[] receivedData = udpClient.EndReceive( asyncResult, ref remoteEP );
        // EndReceive worked and we have received data and remote endpoint
    }
    catch (Exception ex)
    {
        // EndReceive failed and we ended up here
    }
} 
else
{
    // The operation wasn't completed before the timeout and we're off the hook
}

这是很久以前的事情了!现在看起来还不错。WaitOne也会返回一个结果,您可以使用它来确定是否已超时。 - weston

4

实际上,看起来 UdpClient 在超时方面存在问题。我试图编写一个只包含 Receive 方法的线程服务器来获取数据并将其添加到队列中。多年来,我一直用 TCP 做这样的事情。期望的是循环在接收到请求方发来的消息前一直阻塞在接收处。然而,即使将超时设置为无限大:

_server.Client.ReceiveTimeout = 0; //block waiting for connections
_server.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 0);

套接字在大约3分钟后超时。

我找到的唯一解决方法是捕获超时异常并继续循环。这隐藏了微软的错误,但未能回答为什么会发生这种情况的根本问题。


1
我猜内部超时时间大约为200000毫秒? - Christopher Stevenson

3
你可以像这样做:

你可以这样操作:

udpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 5000);

3

您可以使用ReceiveTimeout属性。


1
ReceiveTimeout 只适用于同步调用(即 Receive 方法)。 - Mauro Sampietro

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接