等待具有超时的UDPClient.ReceiveAsync

9
我正在使用以下方式使用UDPClient。
dim c = New UDPClient(port)
client.CLient.ReceiveTimeout = 1
await client.ReceiveAsync()

然而,即使我设置了超时时间,但是等待并没有终止或抛出异常。这种情况正常吗?

4个回答

7

是的。 Socket 上的异步方法不实现超时。如果需要异步操作超时,您需要自己创建它们(例如,使用Task.DelayTask.WhenAny)。


8
举个例子会让这个答案更加完善。 - Poul Bak

7
在MSDN Library的Socket.ReceiveTimeout文章中明确提到:

获取或设置一个值,该值指定同步接收调用超时的时间。

加重强调。当您使用ReceiveAsync()时,您正在执行相反的操作,与同步接收相反。解决方法是使用System.Timers.Timer,在调用前启动计时器,在调用后停止计时器。在已过时间的事件处理程序中关闭套接字,以便ReceiveAsync()方法以ObjectDisposed异常终止。


好主意。如果另一个线程正在等待它,像这样关闭套接字是否存在任何线程安全问题? - bradgonesurfing
我无法在没有足够信息的情况下回答这个问题。然而,让多个线程异步地从套接字读取数据永远不会是一个问题,而是不可能的。 - Hans Passant

4

最近我遇到了这个问题,以下是我的解决方法:

async Task Listen(IPEndPoint ep, int timeout)
{
    using (var udp = new UdpClient(ep))
    {
        var result = await Task.Run(() =>
        {
            var task = udp.ReceiveAsync();
            task.Wait(timeout);
            if (task.IsCompleted)
            { return task.Result; }
            throw new TimeoutException();
        });

        Receive(result); // use the result
    }
}

3
请注意,如果超时时间到达,读取操作仍然会继续运行,并最终丢弃接收的数据。如果发生超时,您只能在关闭整个套接字的情况下使用此技术。 - usr
@usr 如果udp客户端在using语句中,一旦udp客户端超出范围,套接字不会被关闭吗? - GrixM

1

就我个人而言,这是我的做法(也可能与取消令牌的组合一起使用):

public static async Task<byte[]> SendReceiveUdpAsync(IPEndPoint endPoint, byte[] packet, int timeout, CancellationToken cancellationToken)
{
    using var client = new UdpClient(endPoint.AddressFamily);
    await client.SendAsync(packet, endPoint, cancellationToken).ConfigureAwait(false);
    var task = client.ReceiveAsync(cancellationToken);
    var index = Task.WaitAny(new [] { task.AsTask() }, timeout, cancellationToken);
    if (index < 0)
        return null;

    return task.Result.Buffer;
}

技巧在于等待UDP接收任务在Task.WaitAny调用中。


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