通过超时取消C#4.5 TcpClient ReadAsync
通过超时取消TcpClient ReadAsync操作并在.NET 4.5中捕获此超时事件的正确方法是什么 TcpClient.ReadTimeout似乎应用于只读同步 更新:通过超时取消C#4.5 TcpClient ReadAsync,c#,timeout,tcpclient,C#,Timeout,Tcpclient,通过超时取消TcpClient ReadAsync操作并在.NET 4.5中捕获此超时事件的正确方法是什么 TcpClient.ReadTimeout似乎应用于只读同步 更新: 尝试应用此处描述的方法 但它从不因超时而取消。有什么问题吗?所以我知道那是很久以前的事了 但谷歌仍然开车送我到这里 我看到没有一个标记为答案 对我来说,我就是这样解决的 我做了一个扩展来添加一个需要额外超时的ReadAsync方法 public static async Task<int> ReadAsync
尝试应用此处描述的方法
但它从不因超时而取消。有什么问题吗?所以我知道那是很久以前的事了 但谷歌仍然开车送我到这里 我看到没有一个标记为答案 对我来说,我就是这样解决的 我做了一个扩展来添加一个需要额外超时的ReadAsync方法
public static async Task<int> ReadAsync(this NetworkStream stream, byte[] buffer, int offset, int count, int TimeOut)
{
var ReciveCount = 0;
var receiveTask = Task.Run(async () => { ReciveCount = await stream.ReadAsync(buffer, offset, count); });
var isReceived = await Task.WhenAny(receiveTask, Task.Delay(TimeOut)) == receiveTask;
if (!isReceived) return -1;
return ReciveCount;
}
公共静态异步任务ReadAsync(此网络流,字节[]缓冲区,int偏移量,int计数,int超时)
{
var ReciveCount=0;
var receiveTask=Task.Run(异步()=>{ReciveCount=wait stream.ReadAsync(缓冲区、偏移量、计数);});
var isReceived=wait Task.WhenAny(receiveTask,Task.Delay(TimeOut))==receiveTask;
如果(!isReceived)返回-1;
返回ReciveCount;
}
因此,如果返回-1,则表示读取超时编辑:以下要点是我为此所做的一个解决方法。 原件: 我真的很喜欢你的答案,并且做了我自己的版本,我认为值得分享:
public static class TcpStreamExtension
{
public static async Task<int> ReadAsyncWithTimeout(this NetworkStream stream, byte[] buffer, int offset, int count)
{
if (stream.CanRead)
{
Task<int> readTask = stream.ReadAsync(buffer, offset, count);
Task delayTask = Task.Delay(stream.ReadTimeout);
Task task = await Task.WhenAny(readTask, delayTask);
if (task == readTask)
return await readTask;
}
return 0;
}
}
公共静态类tcpstream扩展
{
公共静态异步任务ReadAsyncWithTimeout(此网络流,字节[]缓冲区,整数偏移量,整数计数)
{
if(stream.CanRead)
{
Task readTask=stream.ReadAsync(缓冲区、偏移量、计数);
Task delayTask=Task.Delay(stream.ReadTimeout);
任务任务=等待任务。WhenAny(readTask,delayTask);
如果(任务==readTask)
返回等待读取任务;
}
返回0;
}
}
它基本上是一样的,只是格式稍有不同,可读性更强(对我来说),更重要的是它没有使用任务
编辑:
以上这些乍一看似乎不错,但我发现它会导致一些问题。如果没有数据进入,readAsync调用似乎会泄漏,在我的例子中,它似乎会在以后的写入中读取数据,并且数据基本上是在不再使用的内存中的某个位置返回的 将CancellationToken
传递给ReadAsync()
不会增加太多价值,因为它只在之前检查令牌的状态:
//如果请求取消,请提前完成任务。
//否则,返回表示开始/结束方法的任务。
返回cancellationToken.IsCancellationRequested
? Task.FromCancelled(cancellationToken)
:BeginEndardAsync(缓冲区、偏移量、计数);
通过等待ReadAsync()
或timout任务按如下方式完成,您可以很容易地自己添加timout机制:
byte[]buffer=新字节[128];
TimeSpan超时=TimeSpan.FromSeconds(30);
var readTask=stream.ReadAsync(buffer,0,buffer.Length);
var timeoutTask=Task.Delay(超时);
等待任务。WhenAny(读取任务、超时任务);
如果(!readTask.IsCompleted)
{
抛出新的TimeoutException($“连接在{timeout}之后超时”);
}
我没有在TcpClient
上看到ReadAsync
。抱歉,这是NetworkStream。ReadAsync读取是否会导致套接字中的数据不一致?我相信不能保证ReciveCount的值会被更新,因为它既不是易失性的,也不是原子性的。或者任务完成和任务等待操作会造成内存障碍?正如此线程所示,在调用线程中变量可能不会更改。如何调用它?如何调用它?
public static class TcpStreamExtension
{
public static async Task<int> ReadAsyncWithTimeout(this NetworkStream stream, byte[] buffer, int offset, int count)
{
if (stream.CanRead)
{
Task<int> readTask = stream.ReadAsync(buffer, offset, count);
Task delayTask = Task.Delay(stream.ReadTimeout);
Task task = await Task.WhenAny(readTask, delayTask);
if (task == readTask)
return await readTask;
}
return 0;
}
}