Sent 2 small packets, received 1 big one

4 views
Skip to first unread message

GilNajera

unread,
Jan 14, 2011, 12:12:47 PM1/14/11
to
Hi everyone!
I have an application that communicates 2 computers using tcp sockets
(winsocks). The most of the time it works fine, but some packets are
received as 1 when they was sent as 2 or 3. I mean, I execute two or
three send commands and receive all the data in one single packet.

The packets are sent every 200 ms (Naggle's algorithm is disabled) and
there is an independent thread receiving on the other side's
application. When a packet is received it is processed immediately,
after that, the receiving is resumed.

I'm not an expert in networking, can anybody tell me why is this
happening, and how can I solve it.

Thanks in advance.

Peter Duniho

unread,
Jan 14, 2011, 12:19:52 PM1/14/11
to
On 1/14/11 9:12 AM, GilNajera wrote:
> Hi everyone!
> I have an application that communicates 2 computers using tcp sockets
> (winsocks). The most of the time it works fine, but some packets are
> received as 1 when they was sent as 2 or 3. I mean, I execute two or
> three send commands and receive all the data in one single packet. [...]

Using TCP, there's no such thing as a "packet" as far as the application
is concerned. The data is simply a stream of bytes, without message
boundaries.

It is fundamental to TCP that your code has to itself manage message
boundaries in the bytes stream.

Oh, and don't disable Nagle.

See http://tangentsoft.net/wskfaq/ for lots of good information. And of
course, the MSDN Winsock documentation.

Pete

Jean-Christophe

unread,
Jan 14, 2011, 12:57:54 PM1/14/11
to
On Jan 14, 6:12 pm, GilNajera

> I have an application that communicates 2 computers using tcp sockets
> (winsocks). The most of the time it works fine, but some packets are
> received as 1 when they was sent as 2 or 3. I mean, I execute two or
> three send commands and receive all the data in one single packet.

> (...)

There's no problem at all here, this is normal behaviour
of the TCP layer which takes care of everything for you.

If I understand your question, my answer is :
no, you won't have ONE receive() for EACH send()
(this sounds more like UDP) - what would be the point anyway ?

If you want to somehow synchronize your sent/received data,
insert specific sequences into your data block before emission,
and extract them after reception. TCP in not concerned.

> I'm not an expert in networking, can anybody tell
> me why is this happening, and how can I solve it.

As long as all the data that has been sent from
one side, is well received on the other side,
there's nothing to solve here. What is the problem ?

David Schwartz

unread,
Jan 14, 2011, 2:54:53 PM1/14/11
to
On Jan 14, 9:12 am, GilNajera <gilnaj...@gmail.com> wrote:
> Hi everyone!
> I have an application that communicates 2 computers using tcp sockets
> (winsocks). The most of the time it works fine, but some packets are
> received as 1 when they was sent as 2 or 3. I mean, I execute two or
> three send commands and receive all the data in one single packet.

There is a 'law' that before anyone can work on TCP/IP, they must
memorize exactly and fully understand the following statement: "TCP is
a byte-stream protocol that does not preserve message boundaries."

Also, you be careful with how you use the term 'packet'. A 'packet' is
something on a network. That you received all the data from one call
to 'receive' doesn't mean that it was received in a single packet and
that you got the data in two calls to 'receive' doesn't mean it wasn't
received in two packets.

> The packets are sent every 200 ms (Naggle's algorithm is disabled) and
> there is an independent thread receiving on the other side's
> application. When a packet is received it is processed immediately,
> after that, the receiving is resumed.

> I'm not an expert in networking, can anybody tell me why is this
> happening, and how can I solve it.

It's happening because there is nothing to stop it from happen nor any
reason it shouldn't happen.

DS

GilNajera

unread,
Jan 14, 2011, 4:15:59 PM1/14/11
to
I understand now, I need to add some separation algorithm for all data
I receive. I will add size information to each send and re-form the
packets when data is received.

Thanks to everyone!

Jean-Christophe

unread,
Jan 15, 2011, 5:15:17 AM1/15/11
to
On Jan 14, 10:15 pm, GilNajera

> I understand now, I need to add some separation algorithm
> for all data I receive. I will add size information to each
> send and re-form the packets when data is received.

In this case, it MAY happend that once
a single large block of data has been sent,
it will be received in several recv() calls.

So :

- Include the data block size in the very first
bytes of the data block : it will be received first.

- Loop on recv() until the received data
has reached the expected block size.

- Implement time-out, status check and so on
to avoid being stuck in infinite reception loop.

Also, it MAY happend that, although data block size
were set in data headers, one single call to recv()
returns one data buffer with the tail of block N-1
*and* the head of block N.

- You will have to split the data buffer
to extract correctly block N-1 and block N.
Include a recognizable IDentification sequence to help
localize the header in order to split blocks correctly.

HTH

GilNajera

unread,
Jan 17, 2011, 3:50:10 PM1/17/11
to
Solved!

The first 2 characters in every 'send' are the size of data.

If received size is greater than expected size, I make a loop to
process each received block. If the las block is incomplete, another
recv is done and when that block is complete, it is processed.

Thank you all!

Peter Duniho

unread,
Jan 17, 2011, 5:41:50 PM1/17/11
to
On 1/17/11 12:50 PM, GilNajera wrote:
> Solved!

Maybe not. That depends on what you actually wrote in your code.

> The first 2 characters in every 'send' are the size of data.

You might receive only a single character. You need to be able to
reconstruct the 16-bit size you're sending from two individually
received bytes.

> If received size is greater than expected size, I make a loop to
> process each received block. If the las block is incomplete, another
> recv is done and when that block is complete, it is processed.

Your code should be more generalized. At a minimum, it should have an
idea of how much data it needs before doing the next useful thing, and
then read that much data in a loop. So when looking for the size, you
need that to be 2 bytes, then after the size has been successfully read,
it's the value of that size.

Ideally, your socket i/o code will be divorced from the message-parsing
altogether. For more efficient use of the system resources, you should
read as much data as is available at the moment, storing it in
application-level buffers, so that the OS buffers can be made available
for more network data.

Then at a higher level of abstraction, you can do the "read as many
bytes from the application buffer as I can deal with at the moment".

Pete`

GilNajera

unread,
Jan 18, 2011, 10:43:51 AM1/18/11
to
Hi Pete!

Let me explain better:

> You might receive only a single character.  You need to be able to
> reconstruct the 16-bit size you're sending from two individually
> received bytes.
>

> Your code should be more generalized.  At a minimum, it should have an
> idea of how much data it needs before doing the next useful thing, and
> then read that much data in a loop.  So when looking for the size, you
> need that to be 2 bytes, then after the size has been successfully read,
> it's the value of that size.

When data is incomplete, a new recv is done waiting only for the
missing amount (if I expect 200 bytes and receive 100, I will wait for
100), but not forever, there is a timeout. If the received data is one
byte, I will wait for another, then again for the size indicated by
those two. I could use a single byte to indicate size, but I preffer
to send more than 255 bytes at a time.

> Ideally, your socket i/o code will be divorced from the message-parsing
> altogether.  For more efficient use of the system resources, you should
> read as much data as is available at the moment, storing it in
> application-level buffers, so that the OS buffers can be made available
> for more network data.

Actually, I'm reading the double of the max packet size, I don't know
how to read all that's in buffer at some moment, that would be nice.

Thanks

Jean-Christophe

unread,
Jan 18, 2011, 12:56:04 PM1/18/11
to
On Jan 18, 4:43 pm, GilNajera

> I don't know how to read all that's in buffer at some moment

Call recv() with the last parameter set
to MSG_PEEK : the function will return
the number of bytes pending to receive :

int nb = recv( sock, buffer, length, MSG_PEEK );

MSG_PEEK :
Peek at the incoming data. The data is
copied into the buffer but is not removed
from the input queue. The function then returns
the number of bytes currently pending to receive.

If you're using a blocking socket, you may also
want to call the select() function to determine
the readability of the socket before calling recv()

HTH

Reply all
Reply to author
Forward
0 new messages