C# 在网络流上设置 WriteTimeout/ReadTimeout 没有区别吗? [英] C# Setting WriteTimeout / ReadTimeout on Network Stream Makes No Difference?

查看:53
本文介绍了C# 在网络流上设置 WriteTimeout/ReadTimeout 没有区别吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的 Xamarin.Forms 应用程序中有以下方法代码

using (TcpClient client = new TcpClient(ip, port))使用 (NetworkStream 流 = client.GetStream()){byte[] messageBytes = PrepareMessageBytes();////设置这些接缝无效//stream.WriteTimeout = (int)TimeSpan.FromSeconds(10).TotalMilliseconds;stream.ReadTimeout = (int)TimeSpan.FromSeconds(10).TotalMilliseconds;////我已经在上面设置了读写超时,但是当//碰到这一行,应用程序无限期挂起?//我希望在 10 秒后,一个 IOException//会被抛出await stream.WriteAsync(messageBytes, 0, messageBytes.Length);流.Flush();字节[]缓冲区=新字节[1024];StringBuilder builder = new StringBuilder();int bytesRead = 0;而 (stream.DataAvailable){bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length);builder.AppendFormat("{0}", Encoding.ASCII.GetString(buffer, 0, bytesRead));}string msg = receivedMessage.ToString();}

在上面,我已将写入和读取超时设置为 10 秒.我知道我的代码挂起:

等待流.WriteAsync(...)

,但我希望在 10 秒后,将抛出 IOException.根据 MS 文档,异步写入/读取并非如此.

如何为 WriteAsync/ReadAsync 方法的调用设置超时时间?

更新 - 基于 STEPHEN 评论的第二次尝试

根据 Stephen 的评论,我更新了代码并将其包装到 try..catch 中以处理 OperationCancelledException.但现在这导致的问题比以前更多,而且应用程序在大部分时间仍会挂起:

试试{使用 (TcpClient 客户端 = 新 TcpClient(ip, port))使用 (NetworkStream 流 = client.GetStream())使用 (var writeCts = new CancellationTokenSource(TimeSpan.FromSeconds(10))){byte[] messageBytes = PrepareMessageBytes();await stream.WriteAsync(messageBytes, 0, messageBytes.Length, writeCts.Token);等待流.FlushAsync();字节[]缓冲区=新字节[1024];StringBuilder builder = new StringBuilder();int bytesRead = 0;而 (stream.DataAvailable){使用 (var readCts = new CancellationTokenSource(TimeSpan.FromSeconds(10)))bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length, readCts.Token);builder.AppendFormat("{0}", Encoding.ASCII.GetString(buffer, 0, bytesRead));}string msg = receivedMessage.ToString();}catch (OperationCancelledException ex){Debug.WriteLine(ex.Message);}

解决方案

如何为 WriteAsync/ReadAsync 方法的调用设置超时时间?

您使用带有 CancellationToken 参数的重载:

using (TcpClient client = new TcpClient(ip, port))使用 (NetworkStream 流 = client.GetStream())使用 (var writeCts = new CancellationTokenSource(TimeSpan.FromSeconds(10))){byte[] messageBytes = PrepareMessageBytes();await stream.WriteAsync(messageBytes, 0, messageBytes.Length, writeCts.Token);等待流.FlushAsync();字节[]缓冲区=新字节[1024];StringBuilder builder = new StringBuilder();int bytesRead = 0;而 (stream.DataAvailable){使用 (var readCts = new CancellationTokenSource(TimeSpan.FromSeconds(10)))bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length, readCts.Token);builder.AppendFormat("{0}", Encoding.ASCII.GetString(buffer, 0, bytesRead));}string msg = receivedMessage.ToString();}

<块引用>

我预计 10 秒后,将抛出 IOException.

当使用取消令牌时,预计会出现 OperationCanceledException.从技术上讲,取消令牌可用于多种取消场景 - 代码决定不再需要完成操作、用户手动取消操作或出现超时.OperationCanceledException 是泛型异常类型,意思是已取消".

I have following method code in my Xamarin.Forms application

using (TcpClient client = new TcpClient(ip, port))
using (NetworkStream stream = client.GetStream())
{
    byte[] messageBytes = PrepareMessageBytes();

    //
    // Setting these seam to have no effect
    //
    stream.WriteTimeout = (int)TimeSpan.FromSeconds(10).TotalMilliseconds;
    stream.ReadTimeout = (int)TimeSpan.FromSeconds(10).TotalMilliseconds;

    //
    // I have set read and write timeouts above but when 
    // hitting this line, app hangs indefinitely?  
    // I would expect that after 10 seconds, a IOException
    // will be thrown
    await stream.WriteAsync(messageBytes, 0, messageBytes.Length);
    stream.Flush();

    byte[] buffer = new byte[1024];
    StringBuilder builder = new StringBuilder();
    int bytesRead = 0;

    while (stream.DataAvailable)
    {
        bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length);
        builder.AppendFormat("{0}", Encoding.ASCII.GetString(buffer, 0, bytesRead));
    }

    string msg = receivedMessage.ToString();
} 

Above, I have set both Write and Read timeouts to 10 seconds. I know my code hangs on call to:

await stream.WriteAsync(...)

, but I would expect that after 10 seconds, an IOException will be thrown. Based on MS documentation, that is not the case for async writes/reads.

How do I set timeout for calls to WriteAsync / ReadAsync methods?

UPDATE - 2ND ATTEMPT BASED ON STEPHEN'S COMMENT

Based on Stephen's comment, I updated the code and wrapped it into try..catch to handle OperationCancelledException. But this is causing even more issues now than before and the App will still hang most of the time:

try
{
    using (TcpClient client = new TcpClient(ip, port))
    using (NetworkStream stream = client.GetStream())
    using (var writeCts = new CancellationTokenSource(TimeSpan.FromSeconds(10)))
    {
        byte[] messageBytes = PrepareMessageBytes();

        await stream.WriteAsync(messageBytes, 0, messageBytes.Length, writeCts.Token);
        await stream.FlushAsync();

        byte[] buffer = new byte[1024];
        StringBuilder builder = new StringBuilder();
        int bytesRead = 0;

        while (stream.DataAvailable)
        {
            using (var readCts = new CancellationTokenSource(TimeSpan.FromSeconds(10)))
                bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length, readCts.Token);
            builder.AppendFormat("{0}", Encoding.ASCII.GetString(buffer, 0, bytesRead));
        }

        string msg = receivedMessage.ToString();
    }
catch (OperationCancelledException ex)
{
    Debug.WriteLine(ex.Message);
}

解决方案

How do I set timeout for calls to WriteAsync / ReadAsync methods?

You use the overload that takes a CancellationToken parameter:

using (TcpClient client = new TcpClient(ip, port))
using (NetworkStream stream = client.GetStream())
using (var writeCts = new CancellationTokenSource(TimeSpan.FromSeconds(10)))
{
    byte[] messageBytes = PrepareMessageBytes();

    await stream.WriteAsync(messageBytes, 0, messageBytes.Length, writeCts.Token);
    await stream.FlushAsync();

    byte[] buffer = new byte[1024];
    StringBuilder builder = new StringBuilder();
    int bytesRead = 0;

    while (stream.DataAvailable)
    {
        using (var readCts = new CancellationTokenSource(TimeSpan.FromSeconds(10)))
            bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length, readCts.Token);
        builder.AppendFormat("{0}", Encoding.ASCII.GetString(buffer, 0, bytesRead));
    }

    string msg = receivedMessage.ToString();
}

I would expect that after 10 seconds, an IOException will be thrown.

When using cancellation tokens, expect an OperationCanceledException. Technically, cancellation tokens can be used for a wide variety of cancellation scenarios - the code decides it doesn't need to complete the operation anymore, the user manually canceled the operation, or there was a timeout. OperationCanceledException is the generic exception type meaning "canceled".

这篇关于C# 在网络流上设置 WriteTimeout/ReadTimeout 没有区别吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆