2

I have a server that sends telemetry data of varying size to receivers, or as I'll call them, clients, via NetworkStream. I aim for maximum speed, so I want minimal delays. The frequency is uncontrolled, so I'd like to use an infinite loop in my clients, that uses NetworkStream.Read to read the data, process it, then repeat.

My problem is that sometimes, if two packets are sent very quickly, and a client has a slow internet connection, the two packets will be received as a continous stream, resulting unprocessable data. A half-solution I found (mostly to confirm that this is indeed the error) is to have a small delay after/before each transmission, using System.Threading.Thread.Sleep(100), but not only I find Sleep a botchy solution, it's inconsistent, as it also slows down clients with a good connection, and the problem may persist with an even worse connection.

What I'd like to do is to have the server send a gap between each transmission, providing a separation regardless of internet speed, as NetworkStream.Read should finish after the current continous stream ends. I don't understand deeply the working of a NetworkStream, and have no idea what a few bytes of empty stream look like or how it could be implemented. Any ideas?

Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
GZoltan
  • 23
  • 5

2 Answers2

4

I would strong advise changing the protocol instead if you possibly can. TCP is a stream-based protocol, and any attempt to effectively ignore that is likely to be unreliable.

Instead, I'd suggest changing to make it a stream of messages where each message has a prefix indicating the length of the body of the message. That way it doesn't matter if a particular message is split across multiple packets or received in the same packet as other messages. It also makes reading easier for clients: they know exactly how much data to read, so can just do that in a simple loop.

If you're concerned that the length prefix will introduce too much overhead (if the data is often small) you could potentially make the protocol slightly more complicated with a single message containing a whole batch of information (multiple telemetry items).

But fundamentally, it's worth assuming that the data will be split into multiple packets, combined again etc. Don't assume that one write operation corresponds to one read operation.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • My concern with that method is that the point of having multiple transmissions here is to have the most up-to-date information. If I received a continous stream, and then separated it, only the last section would be relevant. If I could separate it while reading, all transmissions could be utilized to increase precision. – GZoltan May 27 '18 at 17:23
  • @ProfessorFireball: I'm afraid I don't quite understand. You can design the protocol however you need, but the important point is to specify how much data you're about to send before you send it, so that the receiving side is able to understand how much data to read. I think I'd need an awful lot more context to understand your comment, but I doubt that it would make my suggestion infeasible. – Jon Skeet May 27 '18 at 21:24
1

You don't specifically mention the ProtocolType you're using on your NetworkStream but TCP is bound to fail your requirements. Intermediate routers/switches have no way to know your intent is to separate packets by time and will not respect that desire. Furthermore, TCP, being stream oriented, delivers packets in order, and it has error correction against dropped packets and corrupt packets. On any occurrence of one or the other it will hold all further packets until the error packet is retransmitted - and then you'll probably get them all in a bunch.

Use UDP and implement throttling on the receiving (i.e., client) side - throwing out data if you're falling behind.

davidbak
  • 5,775
  • 3
  • 34
  • 50
  • Done some reading, UDP is indeed what I should have used. This is another problem of mine where the solution is that there's no solution, do something else. – GZoltan May 27 '18 at 18:08
  • UDP has it's own issues to be aware of: it'll drop packets and deliver them out of order. The first might very well not be an issue for you and you can fix the second with timestamps/sequence numbers in your data packets. – davidbak May 27 '18 at 18:34
  • @ProfessorFireball, there certainly is a solution, as outlined nicely in the other answer. TCP can work perfectly well for what you're trying to do, if you use it correctly. – glenebob May 27 '18 at 19:30