等待 UDPClient.ReceiveAsync 超时

问题描述 投票:0回答:5

我正在使用 UDPClient,如下所示

dim c = New UDPClient(port)
client.CLient.ReceiveTimeout = 1
await client.ReceiveAsync()

但是,await 不会终止或抛出异常 虽然我设置了超时。这是正常的吗 行为?

.net timeout udpclient async-await
5个回答
7
投票

MSDN Library 文章中明确提到了 Socket.ReceiveTimeout:

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

添加了强调。使用 ReceiveAsync() 时,您正在执行与同步接收相反的操作。解决方法是使用 System.Timers.Timer,在调用之前启动并在调用之后停止。关闭 Elapsed 事件处理程序中的套接字,以便 ReceiveAsync() 方法终止并出现 ObjectDispose 异常。


7
投票

是的。

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


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
    }
}

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;
}

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


0
投票

你也可以给

ReceiveAsync
函数一个
CancellationToken
,让这个token在超时后过期。

private async Task ReceiveDataWithoutTokenAsync(int timeoutInMs)
{
    using (CancellationTokenSource cancellationTokenSource = new())
    {
        cancellationTokenSource.CancelAfter(timeoutInMs);
        await UdpClient.ReceiveAsync(cancellationTokenSource.Token);
    }
}

或者,如果您已有令牌,则可以链接外部令牌和超时令牌。

private async Task ReceiveDataWithExternalTokenAsync(int timeoutInMs, CancellationToken externalToken)
{
    using (CancellationTokenSource internalCancellationTokenSource = new())
    {
        using (CancellationTokenSource linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(internalCancellationTokenSource.Token, externalToken))
        {
            internalCancellationTokenSource.CancelAfter(timeoutInMs);
            await UdpClient.ReceiveAsync(linkedTokenSource.Token);
        }
    }
}

根据如何:监听多个取消请求

© www.soinside.com 2019 - 2024. All rights reserved.