证据在这里。
知道这段代码有什么问题吗?
[TestMethod]
public void TestTest()
{
var tcp = new TcpClient() { ReceiveTimeout = 5000, SendTimeout = 20000 };
tcp.Connect(IPAddress.Parse("176.31.100.115"), 25);
bool ok = Read(tcp.GetStream()).Wait(30000);
Assert.IsTrue(ok);
}
async Task Read(NetworkStream stream)
{
using (var cancellationTokenSource = new CancellationTokenSource(5000))
{
int receivedCount;
try
{
var buffer = new byte[1000];
receivedCount = await stream.ReadAsync(buffer, 0, 1000, cancellationTokenSource.Token);
}
catch (TimeoutException e)
{
receivedCount = -1;
}
}
}
我终于找到了解决方法。使用 Task.WaitAny 将异步调用与延迟任务 (Task.Delay) 结合起来。当 io 任务之前的延迟过去时,关闭流。这将迫使任务停止。您应该正确处理 io 任务上的异步异常。并且您应该为延迟任务和 io 任务添加一个延续任务。
它也适用于 TCP 连接。关闭另一个线程中的连接(您可以认为它是延迟任务线程)会强制所有使用/等待此连接的异步任务停止。
--EDIT--
@vtortola 建议的另一个更干净的解决方案:使用取消令牌来注册对 Stream.Close 的调用:
async ValueTask Read(NetworkStream stream, TimeSpan timeout = default)
{
if(timeout == default(TimeSpan))
timeout = TimeSpan.FromSeconds(5);
using var cts = new CancellationTokenSource(timeout); //C# 8 syntax
using(cts.Token.Register(() => stream.Close()))
{
int receivedCount;
try
{
var buffer = new byte[30000];
receivedCount = await stream.ReadAsync(buffer, 0, 30000, tcs.Token).ConfigureAwait(false);
}
catch (TimeoutException)
{
receivedCount = -1;
}
}
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)