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?
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.
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.
Related
I have created a simple server that currently uses a TCP socket for all my packeting needs. If some data transfer is best used with TCP and others with UDP, what is the most effective way to use them in tandem? Can you simply have 2 sockets? I cannot find example code that shows best practices for this, and it seems like something that would be difficult to debug if done improperly. Thanks!
There is nothing to prevent you from having 2 listening sockets, one each for TCP and UDP. However, the communication method is generally chosen in advance for a given application. For example, the syslog protocol is almost always implemented only with UDP. HTTP on the other hand is pretty much always implemented only over TCP. There are a few protocols that often support both (NTP, DNS are examples).
It would be extremely rare to find a single application that allows a single logical data stream to use both at the same time, and it would be nigh on impossible to ever get that working reliably.
But otherwise if you do support both mechanisms, debugging is straightforward because each can be treated and debugged in isolation.
TCP is far easier to use if you require reliable sequenced delivery -- and for most applications the obvious choice. Every byte sent via TCP is guaranteed to be delivered in the order you send it (or you will receive a distinct error notification), and the peer operating systems between the two machines will cooperate in attempting retries as needed in case any packets are dropped en route. A lot of stuff you don't need to worry about here. Downsides are: (a) some increased overhead, and (b) "message" boundaries are not respected (that is, TCP delivers a stream of bytes; the receiver won't necessarily get them in the same discrete chunks in which they were sent so you must impose message boundaries yourself).
UDP doesn't guarantee delivery. That is, packets may still be dropped, but with no notice to the sender and it is your (i.e. your application's) responsibility to handle that appropriately. Likewise, it is possible for packets to show up in a different order than you sent them (due to different routing paths, for example). On the other hand, the packet you send is the packet you receive so your message boundaries remain intact.
So UDP is often chosen for short "one-shot" or single message notifications, where it's easy to set a timeout at application level, or where each message stands alone and a lost message is non-critical. While TCP is usually the better choice when there is a long-lasting connection or large continuous data streams need to be sent (file transfers and so forth).
Unless you use a raw socket, you must have two separate sockets for UDP and TCP communication.
TCP and UDP are independent OSI Level 4 protocols.
If you use a socket with a default options, it's most likely a TCP socket.
You specify the protocol you want to use when you create a socket - SOCK_STREAM is for TCP and SOCK_DGRAM is for UDP.
C# may have more readable options instead of SOCK_STREAM and SOCK_DGRAM.
If you do use raw sockets, you can distinguish between protocols by parsing IP headers.
I am using Csharp tcp sockets to send data between a client and server.
Now the problem as i see it or as i perceive it is that tcp is a stream protocol and will not push (send) data unless their is a sufficient amount of it.
For instance say i wanted to send some data whatever it is doesnt matter lets just say its 8 bytes long. The behaviour i am seeing is no matter how long i wait it wont send that data unless i push more behind it presumably until i reach the tcp buffer.
So my question is. If i want to send a small amount of data via tcp do i need to append garbage to the end to force the socket to send. ( I wouldnt feel good about this ) or is their an alternative way i can force the front segment of the stream to send.
thanks in advance. i am still learning tcp so excuse the ignorance.
Don't set NoDelay unless you are an expert at TCP/IP and understand its full ramifications. If you haven't read Stevens, don't even think about it.
Here's an example question: if you establish a socket connection and send 8 bytes on it, are the 8 bytes immediately sent or does the Nagle algorithm wait for more data to send? The answer is "the 8 bytes are sent immediately" - but don't consider messing with Nagle until you understand exactly why that is the answer.
Here's another question: in a standard command/response protocol, how much Nagle delay is applied to each packet? The answer: none. Again, you should research why Nagle causes no delays in this common scenario.
If you're not seeing the data sent by 250 milliseconds (the maximum delay caused by Nagle in the worst possible scenario), then there is something else wrong.
You could set the NoDelay property (I think it's what disables Nagle).
For communication with some third-party software, I need to establish an unidirectional connection over TCP. My software only needs to send data to the other side and never will read any data.
Currently I'm using the TcpClient. What would happen if there are incoming packets nonetheless and I never read them? Would they pile up somewhere and lead to some errors or the like? How would I configure the TcpClient to ignore or discard all incoming data?
The whole design is not exactly what I would do, but I can't change the other software and need to bear with this.
Some nice hints on the bits inside a TcpClient would be very helpful!
I think some of the data will be buffered, waiting for you to read it. Not sure how large the buffer size is, however. I don't think it will lead to errors immediately, but if the sender is expecting to be able to write, at some point the write may time out and the other party may choose to close the connection.
Nothing will happen from your point of view. Data will be discarded.
I'm trying to send a large amount of data (more than 50 MB) using C# UdpClient.
So at first I split the data into 65507 byte blocks and send them in a loop.
for(int i = 0; i < packetCount; i++)
myUdpClient.Send(blocks[i], block[i].Length, remoteEndPoint);
My problem is that only the first packets can be received.
During sending the first packet the networkload increases rapidly to 100%, and then the other packets cannot be received.
I want to get as much data throughput as possible.
I'm sorry for my English!
Thanks for your help in advance.
For all those people saying to use TCP....are foolishly wrong. Although TCP is reliable and the window maintained by the kernel it's fairly "set and forget" protocol, but when it comes to the guy wanting to use 100% of his throughput, TCP will not do (it throttles too hard, and the wait for an ACK automatically puts at least 50% trashed because of the RTT).
To the original question, you are sending UDP packets nonstop in that for-loop, the window fills up and then any new data is dropped immediately and doesn't even attempt to go on the line. You are also splitting your data too large. I would recommend building your own throttle mechanism that starts off with 2k segments per second, and slowly ramps up. Each "segment" contains a SEQ (sequence identifier for acknowledgements or ACK) and OFF (offset inside the file for this data set). As the data is being tagged, let the server keep track of these tags. When the other side gets them, it stores the SEQ numbers in an ACK list, and any missing SEQ numbers are placed into a NACK timer list, when the timer runs out (if they haven't been received) it moves to a NACK list. The receiver should send 5 or so ACKs from the ACK list along with up to 5 NACKs in a single transmission every couple seconds or so. If the sender receives these messages and there are any NACKs, it should immediately throttle down and resend the missing fragment before continuing. The data that is ACKed can be freed from memory.
Good luck!
I don't know about .Net implementation specifically, it might be buffering your data, but UDP datagram is normally limited by the link MTU, which is 1500 on normal ethernet (subtract 20 bytes for IP header and 8 bytes of UDP header.)
UDP is explicitly allowed to drop and reorder the datagrams, and there's no flow control as in TCP.
Exceeding the socket send buffer on the sender side will have the network stack ignore following send attempts until the buffer space is available again (you need to check the return value of the send() for that.)
Edit:
I would strongly recommend going with TCP for large file transfers. TCP gives you sequencing (you don't have to keep track of dropped and re-ordered packets.) It has advanced flow control (so fast sender does not overwhelm a slow receiver.) It also does Path MTU discovery (i.e. finds out optimal data packetization and avoids IP fragmentation.) Otherwise you would have to re-implement most of these features yourself.
I hate to say it but you need to sleep the thread. You are overloading your throughput. UDP is not very good for lossless data transfer. UDP is for when you don't mind dropping some packets.
Reliably - no, you won't do it with UDP.
As far as I understand, this makes sense for sending to multiple computers at a time (broadcasting).
In this case,
establish a TCP connection with each of them,
split the data into blocks,
give each block an ID,
send list of IDs to each computer with TCP connection,
broadcast data with UDP,
inform clients (via TCP) that data transmission is over,
than clients should ask to resend the dropped packets
I am working on a little online multiplayer pong game with C# and XNA.
I use sockets to transfer data between two computers on my personnal LAN. It works fine.
The issue is with speed : the transfer is slow.
When I ping the second computer, it shows a latency of 2 ms.
I set up a little timer inside my code, and it shows a latency of about 200 ms.
Even when the server and the client are on the same computer (using 127.0.0.1), the latency still about 15 ms. I consider this as slow.
Here are some fragment of my code :
server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
server.Bind(new IPEndPoint(IPAddress.Any, port));
server.Listen(1);
// Begin Accept
server.BeginAccept(new AsyncCallback(ClientAccepted), null);
in ClientAccepted, I set up a NetworkStream, a StreamReader and a StreamWriter.
This is how I send a message when I want to update the player's location :
string message = "P" + "\n" + player.Position + "\n";
byte[] data = Encoding.ASCII.GetBytes(message);
ns.BeginWrite(data, 0, data.Length, new AsyncCallback(EndUpdate), null);
the only thing EndUpdate do is to call EndWrite.
This is how I receive data :
message = sr.ReadLine();
It dosen't block my game since it's on a second thread.
These are the stuff I tried :
- Use IP instead of TCP
- Use binary message instead of text
- Use IPv6 instead of IPv4
Nothing really did help.
Any thoughts about how I can improve the latency?
Thank you
The latency you're seeing is most likely due to Nagle's algorithm which is used to improve efficiency when sending lots of small packets using TCP. Essentially, the TCP stack collects small packets together and coalesces them into a larger packet before transmitting. This obviously means delaying for a small interval - up to 200ms - to see if any more data is sent, before sending what's waiting in the output buffers.
So try switching off Nagle by setting the NoDelay property to true on the socket.
However, be aware that if you do a LOT of small writes to the socket, that you may lose performance because of the TCP header overhead and processing of each packet. In that case, you'd want to try to collect your writes together into batches if possible.
There are several other meta-issues to consider:
Timer accuracy: Many system timers only update every 15 ms or so. I can't remember the precise value, but if your timings are always multiples of about 15 ms, be suspicious that your timer is not high precision. This is 'probably' not your issue, but keep it in mind.
If you're testing on the same computer, and only running a single core machine, the thread/process switching frequency will dominate your ping times. Not much to do but try to add Sleep(0) calls to allow thread/process swaps after sending data.
TCP/IP transmission settings. As alluded earlier in SocketOptionName.NoDelay. Also as mentioned earlier, consider UDP if you're continuously updating state. Order isn't guaranteed, but for volatile data missing packets are acceptible, as the state will be overridden soon anyway. To avoid using stale packets, add an incrementing value to the packet and never use a packet labelled earlier than the current state.
The difference between tcp and udp should not account for 200 ms, but a combination of other factors can.
Polling vs. Select. If you're polling for received data, the frequency of polling will interfere with receive rate, naturally. I use Socket.Select in a dedicated network thread to wait for incoming data and handle it as soon as possible.
Most networked games don't use TCP but UDP for communications. The problem with that is that data can be easily dropped, which is something you have to account for.
With TCP, there are a number of interactions between the host/server to guarantee data in an ordered manner (another thing you have to account for using UDP, the fact that data is not ordered).
On top of that, the timer in your code has to wait until the bytes bubble up from the unmanaged socket layer through unmanaged code, etc, etc. There is going to be some overhead there that you aren't going to be able to overcome (the unmanaged to managed transition).
You said you tried "IP", and you presumably did that by specifying ProtocolType.Ip, but I don't know what that really means (i.e. I don't know what protocol is chosen 'under the hood') when you combine that with SocketType.Stream.
As well as what casperOne said, if you're using TCP then see whether setting SocketOptionName.NoDelay makes any difference to you.