Edit: I did not do this approach in accordance with a discussion with Stephen Cleary . If you are interested in how I did it differently, look at my answer below.
I am looking for a way to read asynchronously NetworkStreamwith a timeout. Of course, the problem is that there is no way to cancel ReadAsync()on NetworkStream, as it simply ignores it CancellationToken. I read the answer, which suggested closing the stream to revoke the token, but in my case this is not an option, since the Tcp connection should remain open. So I came up with the following code, but I was wondering if it would be better
Task.Run(() => stream.Read(buffer, offset, count)
and just block the thread.
public static class TcpStreamExtension
{
public static async Task<int> ReadAsyncWithTimeout(this NetworkStream stream, byte[] buffer, int offset, int count)
{
CancellationTokenSource cts = new CancellationTokenSource();
bool keepTrying = true;
Timer timer = new Timer(stream.ReadTimeout);
timer.Elapsed += new ElapsedEventHandler((sender, args) => stopTrying(sender, args, cts, out keepTrying));
timer.Start();
try
{
if (stream.CanRead)
{
while (true)
{
if (stream.DataAvailable)
{
return await stream.ReadAsync(buffer, offset, count, cts.Token).ConfigureAwait(false);
}
if (keepTrying)
{
await Task.Delay(300, cts.Token).ConfigureAwait(false);
}
else
{
cts.Dispose();
timer.Dispose();
throw new IOException();
}
}
}
}
catch (TaskCanceledException tce)
{
}
finally
{
cts.Dispose();
timer.Dispose();
}
if (stream.DataAvailable)
{
return await stream.ReadAsync(buffer, offset, count).ConfigureAwait(false);
}
throw new IOException();
}
private static void stopTrying(object sender, ElapsedEventArgs args, CancellationTokenSource cts, out bool keepTrying)
{
keepTrying = false;
cts.Cancel();
}
}
, , , , , IO. , -