I have a client-server program.
I’m sending data like this:
private void Sender(string s,TcpClient sock)
{
try
{
byte[] buffer = Encoding.UTF8.GetBytes(s);
sock.Client.Send(buffer);
}catch{}
}
and on the client side receiving like this:
byte[] buffer = new byte[PacketSize];
int size = client.Client.Receive(buffer);
String request = Encoding.UTF8.GetString(buffer, 0, size);
The problem is that data is not fully received always, sometimes it’s only part of what I have sent. PacketSize is 10240 which is more than the bytes I send. I have also set SendBufferSize and ReceiveBufferSize at both sides.
The worst part is that sometimes data is fully received!
What might be the problem?
The
sizevalue returned byTcpClient.Receiveis not the same as the length of the buffered string you sent. This is because there is no guarantee that when callingReceiveonce you will get back all the data that you sent withSendcall. This behavior is intrinsic to the way TCP works (it’s a stream-, not a message-based data protocol).You cannot solve the problem by using bigger buffers, as the buffers you provide can only limit the amount of data that
Receivereturns. Even if you provide a 1MB buffer and there is 1MB of data to read,Receivecan legitimately return any number of bytes (even just 1).What you need to do is make sure that you have buffered all the data before calling
Encoding.GetString. To do that, you need to know how much data there is in the first place. So at the very least, you need to write the length of the string bytes when sending:When receiving, you will first read the length (which has a known fixed size: 4 bytes) and then start buffering the rest of the data in a temp buffer until you have
lengthbytes (this might take any number ofReceivecalls, so you ‘ll need awhileloop). Only then can you callEncoding.GetStringand get your original string back.Explanation of the behavior you observe:
Even though the network stack of the OS makes pretty much no guarantees, in practice it will usually give you the data one TCP packet brings with one
Receivecall. Since the MTU (maximum packet size) for TCP allows around 1500 bytes for payload, naive code will work fine as long as the strings are less than this size. More than that and it will get split into multiple packets, and oneReceivewill then return only part of the data.