通过超时取消C#4.5 TcpClient ReadAsync

mik*_*ksh 5 c# timeout tcpclient

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

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

更新:
Tried tro应用此处描述的方法取消异步操作

var buffer = new byte[4096];
CancellationTokenSource cts = new CancellationTokenSource(5000);
int amountRead = await tcpClientStream.ReadAsync(buffer, 0, 4096, cts.Token);
Run Code Online (Sandbox Code Playgroud)

但它永远不会超时取消.有什么问题吗?

Kha*_*mar 13

所以我知道这是很长一段时间,但谷歌仍然把我带到这里,我看到没有标记为答案

对我来说,我解决这个问题,我做了一个扩展,添加一个额外超时的方法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;
    }
Run Code Online (Sandbox Code Playgroud)

所以如果它返回-1表示读取超时

  • 读取可能会完成,从而导致套接字中的数据不一致吗? (3认同)

Sve*_*lov 6

编辑:以下要点是我为此所做的解决方法。 https://gist.github.com/svet93/fb96d8fd12bfc9f9f3a8f0267dfbaf68

原来的:

我真的很喜欢Khalid Omar的答案,并做了我自己的版本,我认为值得分享:

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

它或多或少是相同的东西,只是格式略有不同(对我来说)更具可读性,更重要的是它不使用Task.Run我不确定为什么在他的示例中使用它。

编辑:

乍一看上面的内容似乎不错,但我发现它会导致一些问题。如果没有数据进入,readAsync 调用似乎会泄漏,在我的例子中,它似乎读取了稍后的写入,并且数据本质上是在内存中不再使用的位置返回的。