I am using NetworkStream
with TcpClient
.
First I setup my tcp client:
tcp = new TcpClient(AddressFamily.InterNetwork) { NoDelay = true, ReceiveTimeout = 5000};
My main data-receiving loop:
while (true) { //read available data from the device int numBytesRead = await ReadAsync(); Console.WriteLine($"{numBytesRead} bytes read"); //BP2 }
And the actual TCP data reading:
public Task<int> ReadAsync() { var stream = tcp.GetStream(); return stream.ReadAsync(InBuffer, 0, InBuffer.Length); //BP1 }
I have this connected to a testbed which lets me send manual packets. Through setting breakpoints and debugging I have checked that stream.ReadTimeout
takes the value 5000 from tcp
.
If I send data frequently it all works as expected. But if I don't send any data, nothing appears to happen after 5s, no timeout. I see breakpoint BP1
being hit in the debugger but until I send data from my testbed, BP2
is not hit. I can leave it a minute or more and it just seems to sit waiting, but receives data sent after a minute, which appears to be incorrect behavior. After 5 seconds something should happen, surely (an exception as I understand it)?
It's late so I am expecting something really basic but can anyone see what my mistake is and a resolution?
Addendum
OK so when I RTFM for the actual .Net version I'm using (how may times have I been caught out by MS defaulting to .Net Core 3, I did say it was late) I see in the remarks sectio for ReadTimeout
:
This property affects only synchronous reads performed by calling the Read method. This property does not affect asynchronous reads performed by calling the BeginRead method.
I'm unclear now if I can use modern awaitable calls at all to read socket data safely and with a timeout specifically. It's working except for the timeout but I'm not sure how given ReadAsync
has no override in NetworkStream
. Must I do some ugly hack or is there a simple solution?
In my case 5000 is the longest I can expect not to receive data before concluding there is a problem - the protocol has no ping mechanism so if nothing appears I assume the connection is dead. Hence thinking an Async read with a 5000ms timeout would be nice and neat.