Значение size
, возвращаемое TcpClient.Receive
, не совпадает с длиной буферизованной строки, которую вы отправили.Это связано с тем, что нет гарантии, что при вызове Receive
один раз вы получите обратно все данные, которые вы отправили с Send
вызовом.Такое поведение является неотъемлемой частью работы TCP (это потоковый, а не протокол данных на основе сообщений).
Вы не можете решить проблему, используя большие буферы, поскольку предоставленные вами буферы могут только предел количество данных, которое Receive
возвращает.Даже если вы предоставляете буфер размером 1 МБ и данные для чтения 1 МБ, Receive
может законно вернуть любое количество байтов (даже всего 1).
Что вам нужно сделать, это убедиться, что вы буферизироваливсе данные перед звонком Encoding.GetString
.Чтобы сделать это, вам нужно знать, сколько данных в первую очередь.Таким образом, по крайней мере, вам нужно записать длину байтов строки при отправке:
byte[] buffer = Encoding.UTF8.GetBytes(s);
byte[] length = BitConverter.GetBytes(buffer.Length);
sock.Client.Send(length);
sock.Client.Send(buffer);
При получении вы сначала прочитаете длину (которая имеет известный фиксированный размер: 4 байта), а затемначинайте буферизовывать оставшиеся данные во временном буфере до тех пор, пока у вас не будет length
байт (это может занять любое количество вызовов Receive
, поэтому вам понадобится цикл while
).Только тогда вы можете позвонить Encoding.GetString
и вернуть исходную строку.
Объяснение поведения, которое вы наблюдаете:
Даже если сетевой стек ОС делает довольномного никаких гарантий, на практике обычно выдает данные, которые приносит один пакет TCP с одним вызовом Receive
.Поскольку MTU (максимальный размер пакета) для TCP допускает около 1500 байт для полезной нагрузки, простой код будет работать нормально, пока строки меньше этого размера.Более того, он будет разбит на несколько пакетов, и один Receive
вернет только часть данных.