问题
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);
}
回答1:
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".
来源:https://stackoverflow.com/questions/54816114/c-sharp-setting-writetimeout-readtimeout-on-network-stream-makes-no-difference