C# 在网络流上设置 WriteTimeout/ReadTimeout 没有区别吗? [英] C# Setting WriteTimeout / ReadTimeout on Network Stream Makes No Difference?
问题描述
我的 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屋!