Abnormal C # socket latency

I am working on a small multiplayer online floor with C # and XNA.

I am using sockets to transfer data between two computers on my local network. It works great.

Speed ​​issue: Transfer is slow.

When I ping the second computer, it shows 2ms latency. I have set up a little timer inside my code and it shows a latency of about 200ms. Even when the server and client are on the same machine (using 127.0.0.1), the timeout is still around 15ms. I find it slow.

Here is a snippet 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 have configured NetworkStream, StreamReader and 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 does is call EndWrite. This is how I get the data:

message = sr.ReadLine();

      

It does not block my game, as it is on the second thread.

Here's what I've tried: - Use IP instead of TCP - Use binary message instead of text - Use IPv6 instead of IPv4 Nothing really helped.

Any thoughts on how I can improve latency?

thank

0


source to share


4 answers


The latency you see is most likely due to the Nagle algorithm , which is used to improve efficiency when sending a large number of small packets using TCP. Basically, the TCP stack gathers small packets together and bundles them into a larger packet before transmission. This obviously means a delay for a small interval - up to 200ms - to see if more data has been sent, before sending the pending data in the output buffers.

So try disabling Nagle by setting the NoDelay property to true on the socket.



However, keep in mind that if you are doing a small write to the socket, you may lose performance due to the TCP header overhead and processing of each packet. In this case, you will want to try to piece your notes together in batches, if possible.

+9


source


Most network games don't use TCP, but UDP for communication. The problem is that the data can be easily discarded, which is what you need to consider.

In TCP, there are a number of interactions between the host and the server to ensure the data is in an ordered order (another thing that you should consider when using UDP is the fact that the data is not in order).



Also, the timer in your code has to wait until bytes come out of the unmanaged socket through unmanaged code, etc. etc. There will be some overhead that you will not be able to overcome (unmanaged managed transition).

+2


source


There are several other meta questions:

  • Timer Accuracy: Many system timers only update every 15ms or so. I don't remember the exact value, but if your timings are always multiples of about 15ms, be suspicious that your timer is not highly accurate. This is "probably" not your problem, but keep this in mind.

  • If you are testing on a single machine and only running a single core machine, the thread / process switching frequency will dominate during your ping. Not much, but try adding Sleep (0) calls to allow thread / process exchange after sending data.

  • TCP / IP transmission settings. As mentioned earlier in SocketOptionName.NoDelay. Also, as mentioned earlier, consider UDP if you are constantly updating state. The order is not guaranteed, but for volatile data, skipped packets are acceptable since the state will be overridden anyway. To avoid using outdated packages, add an incremental value to the package and never use a package that is previously marked with the current state. The difference between tcp and udp shouldn't be 200ms, but there could be a combination of other factors.

  • Poll versus choice. Naturally, if you are polling the received data, the polling rate will interfere with the receive rate. I am using Socket.Select on a dedicated network thread to wait for incoming data and process it as soon as possible.

+2


source


You said you tried "IP" and you presumably did it by specifying ProtocolType.Ip, but I don't know what that means (i.e. I don't know which protocol is selected "under the hood") when you combine this with SocketType.Stream.

Like what casperOne said, if you are using TCP then see if the SocketOptionName.NoDelay setting is affecting you.

0


source







All Articles