Reputation: 630
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?
Upvotes: 3
Views: 2910
Reputation: 437336
The size
value returned by TcpClient.Receive
is not the same as the length of the buffered string you sent. This is because there is no guarantee that when calling Receive
once you will get back all the data that you sent with Send
call. 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 Receive
returns. Even if you provide a 1MB buffer and there is 1MB of data to read, Receive
can 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:
byte[] buffer = Encoding.UTF8.GetBytes(s);
byte[] length = BitConverter.GetBytes(buffer.Length);
sock.Client.Send(length);
sock.Client.Send(buffer);
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 length
bytes (this might take any number of Receive
calls, so you 'll need a while
loop). Only then can you call Encoding.GetString
and 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 Receive
call. 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 one Receive
will then return only part of the data.
Upvotes: 8