Post by Giuseppe Vitillaro ***@vitillaro.org [hercules-390]Post by ***@yahoo.com [hercules-390]Sorry Jon but I disagree, a blocking receive, with or without a timeout,
is not a predictable amount, except when small messages (i.e.
approximately 500 bytes or less) are involved.
The quantity of data an individual recv call will receive is influenced
by a whole range of factors outside of the receivers control, for
example, the MTU(s) in use between the endpoints, the network
utilization, the load on the sending and/or receiving systems, etc.
Joe has made the same assumption that pretty much everyone new to
sockets programming has made (myself included), that because a lump of
data of n bytes was sent, a lump of data of n bytes will be received.
Ian
Yep. That the TCP socket model, at least for what I understand
from my Comer.
The size returned from a single read() on a socket is just
"unpredictable": you are reading a "stream of bytes" from the socket and
the size of the returned buffers, for each single read(), is influenced by
a great number of parameters.
You may send a single block of N bytes from one side and you may receive
any "partition" of such integer number N, (i_1,i_2,...,i_m), in m
reads from the other side, where (i_1 + i_2 + ... + i_m) = N.
The TCP/IP protocols may only assure that you will receive the correct
number of bytes in an unpredictable number of reads, the correct bytes, in
the correct order, but nothing else.
That's why, usually, over a TCP socket stream, you need an "application
protocol" which allow the applications on the two sides of the socket, to
send and receive application data.
Peppe.
One of the simpler application protocols which may be implemented over a
TCP socket, is a "message passing protocol", where the length of a
"message", a string of bytes for example, is encoded in "network format",
as the "header" of the message.
The "functions" htonl/ntohl, which are almost always presents, as
functions or macros, in any socket library, may be easily used to encode
such "header length" as an unsigned 32 bits integer, in an architecture
indipended format, the easier way to marshall/unmarshall application data.
In such a way, once the message "length" has been received
the message payload may be received looping until the whole
message is recovered in user space buffers:
ptr = (unsigned char *)msg;
...
for ( len = 0; len < length; len += l ) {
l = recv ( q.socket, ptr, length - len, 0 );
ptr += l;
}
The length header itself may be received, before the payload,
with exactly the same loop and a fixed "length" of "sizeof(uint32_t)".
That of course, beside error checking ...;-)
Peppe.