27

After spending way more time than seems reasonable to find an answer to this simple question, I thought I would leave my results here so others don't have to jump through all the hoops and wrong paths that I had just followed.

The problem is that if you use the TcpClient ReadTimeout property and your Read operation actually times out, Microsoft decided to close the socket. This is not expected, not desirable, not done by any other socket implementation I know of, and has no valid reason that this should be the case other than programmer laziness. But this is what Microsoft chose to do.

Anyways, all the workarounds I found, including on this site, had various ways of doing some form of busy polling and some even involved kicking off yet another thread to perform a simple Read call. I'm sorry, but I've got better things to do with my CPU than to sit there and busy poll, especially with many sockets open, so this is not an option for me. After all, this isn't the early 1990's where busy polling was just how you did things. Nowadays, we have this thing called operating systems that take care of these types of things quite efficiently using interrupts.

Anyways, on yet another tangential search I stumbled upon this old blog post:

http://blogs.msdn.com/b/mflasko/archive/2006/02/20/535655.aspx

MSDN Blogs > Mike Flasko's Blog > Handling a timeout when reading network data

The key take aways that tell you the solution on how to properly handle read timeouts are:

At this point one may be tempted to catch the exception and then reissue the read on the same NetworkStream. This strategy can lead to unexpected errors. The best thing to do is to now treat the NetworkStream (socket) as being in an unstable state. This is because when the underlying stack times out, the underlying I/O read gets cancelled. If data comes in at the same time, the data will be lost, resulting in a corrupted data stream.

and the solution:

A better approach is to catch the exception, close the socket or TCPClient and reconnect if necessary.

While I still think this puts unnecessary burden on the user of the API, at least it is the most proper solution I was able to find out of the dozens of sites I looked at trying to figure out to do a semi-proper socket ReadTimeout.

I hope this question/comment saves somebody the hours it took me to find.

Dunk
  • 1,704
  • 1
  • 14
  • 19
  • I've been working with that stuff lately too, If i set timeout to 1000ms and catch the exception, sometimes I may end up delaying some procedures, because its pretty hard to determine if the transmission is really over OR you got a network problem. For example, I have a part of code that transmits a PNG image over the network, code is something like while (true) { try Receive data and put into a 4096 byte buffer breaks on exception; then if no data available, break while; } If I dont put a 1ms thread sleep, (i know it sucks) the dataavailable will return false too soon and image will rip off. – Felype Feb 11 '14 at 06:53
  • Is this a question? I feel like this would be much better if it was in Q&A format even if you are answering your own question. – Tim Lovell-Smith Mar 31 '14 at 21:17
  • The title is the question. I could certainly have asked the question and answered in a separate response, but I did it this way instead. This was the original question I was going to ask but before pressing the Post button I thought I should do enough research so I could ask a more "informed" question. However, I didn't realize how much time that little endeavor would end up taking. In the process, I answered my own question. Since it took so long to come up with an acceptable solution, I thought it would be nice to save others from having to repeat all the hours of research that I had to do. – Dunk Apr 02 '14 at 22:27
  • ...Another alternative would have been to simply not ask the question at all. But I thought this would be helpful to others. – Dunk Apr 02 '14 at 22:28
  • @Dunk Thanks for that Q&A post, I'm struggling with this problem right now. I wrote my TCP Server Client application using ReadTimeout property, catch the exception and reissue the read on the same NetStream. What is interesting, it works on Win 7, but not in Win XP. After receiving IOException from ReadTimeout on Win XP, socket is going to be closed. – Lazureus Nov 04 '14 at 20:55

1 Answers1

3

what you are looking for is the Poll or Select methods, these allow you to wait for data with a timeout without closing the underlying connections:

http://msdn.microsoft.com/en-us/library/system.net.sockets.socket.poll%28v=vs.110%29.aspx http://msdn.microsoft.com/en-us/library/system.net.sockets.socket.select%28v=vs.110%29.aspx

Dieter DHoker
  • 421
  • 3
  • 9