A faster way to communicate using TcpClient?

I am writing a client / server application in C # and this is great. So far, everything is working, and all this is pretty cool. My problem is that I run some delays when sending packets over the connection.

On the client side, I do this:

NetworkStream ns = tcpClient.GetStream(); // Send packet byte[] sizePacket = BitConverter.GetBytes(request.Length); byte[] requestWithHeader = new byte[sizePacket.Length + request.Length]; sizePacket.CopyTo(requestWithHeader, 0); request.CopyTo(requestWithHeader, sizePacket.Length); ns.Write(requestWithHeader, 0, requestWithHeader.Length); // Receive response ns.Read(sizePacket, 0, sizePacket.Length); int responseLength = BitConverter.ToInt32(sizePacket, 0); byte[] response = new byte[responseLength]; int bytesReceived = 0; while (bytesReceived < responseLength) { int bytesRead = ns.Read(response, bytesReceived, responseLength - bytesReceived); bytesReceived += bytesRead; } 

(Remaining exception to exclude exceptions, etc.). The server does the opposite, i.e. blocks it in NetworkStream.Read () until it receives the entire request, then processes it and sends a response using Write ().

The raw Write () / Read () speed is not a problem (that is, sending large packets is fast), but sending several small packets one after another without closing the connection can be terribly slow (delays of 50-100 ms). It is strange that these delays appear on LAN connections with a typical ping time <1 ms, but they do not occur if the server is running on the local host, even if the ping time will be practically the same (at least, the difference should not be on the order of 100 ms). This would make sense to me if I reopened the connection on each packet, causing a lot of handshakes, but I don't know. This is exactly the same as if the server goes into the idle state, it does not synchronize with the client, and then stumbles a bit as it restores what is essentially a lost connection.

So, am I doing this wrong? Is it possible to synchronize the connection between TcpServer and TcpClient so that the server is always ready to receive data? (And vice versa: sometimes processing a request from a client takes several ms, and then the client does not seem to be ready to receive a response from the server until it has enough minutes to wake up after Read () is blocked.)

+6
source share
1 answer

It turns out that my server and client were not completely symmetrical in the end. I noticed, but I didn’t think it mattered. Apparently, this is a huge deal. In particular, the server did this:

 ns.Write(sizePacket, 0, sizePacket.Length); ns.Write(response, 0, response.Length); 

What I changed to this:

 // ... concatenate sizePacket and response into one array, same as client code above ns.Write(responseWithHeader, 0, responseWithHeader.Length); 

And now the delay has completely disappeared, or at least it is not measurable in milliseconds. So something like 100x acceleration right there. \ O /

This is still strange because it writes exactly the same data to the socket as before, so I think the socket receives some secret metadata during the write operation, which are then somehow transferred to the remote socket, which may interpret it as the opportunity to take a nap. Either this, or the first record puts the socket in receive mode, causing it to turn off when it asked to send again before it received anything.

I assume that the implication will be that all this sample code that you find is around, which shows how to write and read from sockets in pieces of a fixed size (often preceded by a single int describing the size of the packet for later, the same , as in my first version), does not mention that this is a very difficult punishment.

+7
source

Source: https://habr.com/ru/post/889013/


All Articles