Salman Younas
Salman Younas

Reputation: 350

Socket Programming: How can I read a specified number of bytes from buffer?

TCP is stream-based protocol. To convert that stream into my messages, I send the size of each message with the message itself. At server side, I first read the first two bytes of message, which have the size. Then I create a byte array, of size equal to the size which was just read. Then I read the bytes into that array. But for some reason, more bytes are being read than specified. How can I read exactly the same number of bytes as I specify?

Here is my code:

while (true)
{
    data = null;
    length = null;

    size = new byte[2];

    handler.Receive(size);

    length += Encoding.ASCII.GetString(size, 0, 2);
    System.Console.WriteLine("Size: " + Int32.Parse(length));

    bufferSize = Int32.Parse(length) + 2;
    bytes = new byte[bufferSize];

    handler.Receive(bytes);

    data += Encoding.ASCII.GetString(bytes, 0, bufferSize);
    System.Console.WriteLine("Data: " + data);
}

This is my server running in Windows PC, written in C#. My client is running in android phone, written in Java.

Upvotes: 0

Views: 3957

Answers (2)

Damien_The_Unbeliever
Damien_The_Unbeliever

Reputation: 239664

It's unclear why you're adding two to the size that's been transmitted - you've already accounted for the two additional bytes for storing the length during your previous receive. So I'd get rid of the +2.

You also need to respect the fact already stated in your question - TCP is a sequence of bytes, not messages. As such, you're never guaranteed whether a call to Receive is going to retrieve an entire "message" or just part of one (or, possible, parts of multiple messages). As such, you need to make sure that you respect the return value from Receive.

We can probably re-write your code as:

while (true)
{
    data = null;
    length = null;

    size = ReceiveExactly(handler,2);

    length = Encoding.ASCII.GetString(size, 0, 2); //Why +=?
    bufferSize = Int32.Parse(length); //Why + 2?
    System.Console.WriteLine("Size: " + bufferSize);

    bytes = ReceiveExactly(handler,bufferSize);

    data += Encoding.ASCII.GetString(bytes, 0, bufferSize);
    System.Console.WriteLine("Data: " + data);
}

Where ReceiveExactly is defined something like this:

private byte[] ReceiveExactly(Socket handler, int length)
{
   var buffer = new byte[length];
   var receivedLength = 0;
   while(receivedLength < length)
   {
      var nextLength = handler.Receive(buffer,receivedLength,length-receivedLength);
      if(nextLength==0)
      {
         //Throw an exception? Something else?
         //The socket's never going to receive more data
      }
      receivedLength += nextLength;
   }
   return buffer;
}

Upvotes: 3

Exceptyon
Exceptyon

Reputation: 1582

to receive a specific amount of bytes use the method

Socket.Receive(Byte[], Int32, Int32, SocketFlags)

rather than Socket.Receive(Byte[]). see spec here

I suspect you want something like

int len = Socket.Receive(bytes, 0, bufferSize, SocketFlags.None);

data += Encoding.ASCII.GetString(bytes, 0, len);
System.Console.WriteLine("Data: " + data);

Upvotes: 3

Related Questions