如何取消Socket.ReceiveFromAsync()?

时间:2019-03-07 11:10:25

标签: c# .net-core udp

我正在使用dotnet core 2.2,并且具有以下UDP侦听器:

var socket = new Socket(ep.AddressFamily, SocketType.Dgram, ProtocolType.Udp);
while (true)
{
    var result = await socket.ReceiveFromAsync(...);
}

现在在某些情况下,我想打断ReceiveFromAsync()通话。但是似乎与TCP情况(即ReceiveAsync())不同,没有ReceiveFromAsync()重载接受CancellationToken

一种选择是将Task.Delay(-1, ct);Task.WhenAny()/Task.WhenAll()一起使用。但是我认为这种解决方案会导致内存泄漏,对吗?我的意思是.ReceiveFromAsync()调用如果被中断,即使在后台也仍然“存在”。还可能导致逻辑中断,因为此类调用将读取UDP数据包并随后将其丢弃?还是我的推理不正确?

另一种想法是让后台工作程序从UDP套接字读取数据并将每个数据包排队。而且这里不会发生任何中断。然后,我将从队列中读取并中断此调用。那会起作用,但绝对需要一些努力。我看到的问题是:线程安全性和性能。

是否有一种更清洁/更简便的方法来处理这种情况?

1 个答案:

答案 0 :(得分:1)

对于“无法取消的” I / O请求,Windows中的标准模式是关闭基础句柄-在这种情况下为套接字。通常,这会导致所有异步(或同步)操作以错误代码完成。

在您的情况下-“暂停” UDP接收器-我认为这种方法特别有意义。 UDP套接字无论如何都不代表打开的连接,因此关闭套接字是最好的解决方案。

关于Task.DelayTask.WhenAny,您的担心是完全正确的。 Task.Delay + Task.WhenAny方法仅取消操作的 wait ,而不取消操作本身。具体来说,它不会取消UDP接收,并且未取消UDP接收操作可能会得到一个数据包,然后该数据包将被“丢失”,因为您的应用程序会忽略它。