[comp.protocols.tcp-ip] Problems with TCP, read

sclayton@wpi.WPI.EDU (Shawn A Clayton) (03/31/91)

I am having problems with TCP, write(), and read(). I want to send and
receive 32 byte structures.  The sockets used are of the type
SOCK_STREAM, and I write() 32 byte chunks into one end (after connect()ing)
and attempt to read() 32 byte chunks from the other end (after listen()ing
and accept()ing).  I write and read many of these 32 byte structures in
succession.  My problem is that if I do no put a sizeable delay in the
send or receive loop, I end up receiving only part of a 32 byte chunk
after a number of chunks have been received.  There is no problem if I put
in a large (the larger the better) delay before each write() or read().
I do not use the )_NDELAY or O_NONBLOCK options.  Sometimes it will work
with a given delay, and other times it does not.  I seems to fail less
the longer the delay is, and more the less the delay.  It also fails more
if the total number of chunks I attempt to send is increased.  Below about
fourty of these chunks there is no problem.  Can anyone help me?  What am
I doing wrong?  I would appreciate any comments or suggestions on what
may be screwing this up.  Please email me - 

	Thanks - Shawn
	sclayton@ee.wpi.edu
-----------------------------------------------------------------------
No, I don't have a signature line!

ted@blia.sharebase.com (Ted Marshall) (04/04/91)

The problem is that TCP is a pure stream protocol that does not preserve
record boundries. Thus, if something delays the processing on some of the
bytes from one of your write()s, your read can easily complete with only the
beginning of what we written.

Since you know that all "records" are 32 bytes, there is a real easy solution:
if your read() completes with less than 32 bytes, add that count to your
buffer pointer, subtract the count from your buffer size, and repeat the read.
Continue this loop until your buffer is full. For example:

	ptr = &buffer[0];
	cnt = sizeof buffer;
	do
	{
		i = read(d, ptr, cnt);
		if (i <= 0)
			<error-processing>
		ptr += i;
		cnt -= i;
	} while (cnt > 0);

-- 
Ted Marshall                                       ted@airplane.sharebase.com
ShareBase Corp., 14600 Winchester Blvd, Los Gatos, Ca 95030     (408)378-7000
The opinions expressed above are those of the poster and not his employer.

0004219666@MCIMAIL.COM (Bob Stine) (04/04/91)

>I am having problems with TCP, write(), and read(). I want to send and
>receive 32 byte structures....
>My problem is that if I do no put a sizeable delay in the
>send or receive loop, I end up receiving only part of a 32 byte chunk
>after a number of chunks have been received.

Shawn,

As you have discovered, TCP does not preserve record boundaries.  One
work-around makes use the value returned by read(), which is the number of the
bytes read.  Keep reading until you get your entire 32 bytes.  I.e.,

  int bf_ln,  /* number of bytes requested */
      bc,     /* byte count returned by read() */
      s;      /* socket */

  struct shawns_struct { /* whatever, 32 bytes worth */} in_rec;

  char *bptr;

  /* get the connection. Then, to load a structure... */

  bf_ln = sizeof(struct shawns_struct);
  bptr  = (char *) in_rec;
  while (bf_ln)
  {
      bc = read(s,bptr,bf_ln);
      if (bc < 1)
         exit(-1);
      bf_ln -= bc;
      bptr  += bc;
   }

Note that I exit if read() returns a value of zero.  In BSD, select() will
indicate that a closed socket is ready to read, but read() will return zero
bytes.  Hence, if the above loop didn't exit when read() returned a zero, then
a closed socket would keep it busy for quite some time... :-)

Regards,

Bob Stine
bstine@MCIMail.com