通过超时取消C#4.5 TcpClient ReadAsync

通过超时取消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

通过超时取消TcpClient ReadAsync操作并在.NET 4.5中捕获此超时事件的正确方法是什么

TcpClient.ReadTimeout似乎应用于只读同步

更新:
尝试应用此处描述的方法


但它从不因超时而取消。有什么问题吗?

所以我知道那是很久以前的事了 但谷歌仍然开车送我到这里 我看到没有一个标记为答案

对我来说,我就是这样解决的 我做了一个扩展来添加一个需要额外超时的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;
    }
}