Dan Webster
Dan Webster

Reputation: 1253

how do you account for when TCP does not get all the bytes in one read

I just read an article that says TCPClient.Read() may not get all the sent bytes in one read. How do you account for this?

For example, the server can write a string to the tcp stream. The client reads half of the string's bytes, and then reads the other half in another read call.

how do you know when you need to combine the byte arrays received in both calls?

Upvotes: 7

Views: 3349

Answers (3)

Jon Skeet
Jon Skeet

Reputation: 1503449

how do you know when you need to combine the byte arrays received in both calls?

You need to decide this at the protocol level. There are four common models:

  • Close-on-finish: each side can only send a single "message" per connection. After sending the message, they close the sending side of the socket. The receiving side keeps reading until it reaches the end of the stream.
  • Length-prefixing: Before each message, include the number of bytes in the message. This could be in a fixed-length format (e.g. always 4 bytes) or some compressed format (e.g. 7 bits of size data per byte, top bit set for the final byte of size data). Then there's the message itself. The receiving code will read the size, then read that many bytes.
  • Chunking: Like length-prefixing, but in smaller chunks. Each chunk is length-prefixed, with a final chunk indicating "end of message"
  • End-of-message signal: Keep reading until you see the terminator for the message. This can be a pain if the message has to be able to include arbitrary data, as you'd need to include an escaping mechanism in order to represent the terminator data within the message.

Additionally, less commonly, there are protocols where each message is always a particular size - in which case you just need to keep going until you've read that much data.

In all of these cases, you basically need to loop, reading data into some sort of buffer until you've got enough of it, however you determine that. You should always use the return value of Read to note how many bytes you actually read, and always check whether it's 0, in which case you've reached the end of the stream.

Also note that this doesn't just affect network streams - for anything other than a local MemoryStream (which will always read as much data as you ask for in one go, if it's in the stream at all), you should assume that data may only become available over the course of multiple calls.

Upvotes: 19

Janman
Janman

Reputation: 698

That is kinda hard to answer, because you can never know when data will arrive, and thats why I usually use a thread for receiving data in my chat program. But you should be able to use something similar to this:

do{
     numberOfBytesRead = myNetworkStream.Read(myReadBuffer,
                                              0, 
                                              myReadBuffer.Length);

     myCompleteMessage.AppendFormat("{0}",
      Encoding.ASCII.GetString(myReadBuffer, 0, numberOfBytesRead));

  }
  while(myNetworkStream.DataAvailable);

Look at this source!

Upvotes: -3

Paul
Paul

Reputation: 5223

You should call read() in a loop. The condition of that loop would check if there is still any data available to be read.

Upvotes: -1

Related Questions