[comp.unix.questions] socket connection dropping characters

putnam@peanuts.nosc.mil (Mike Putnam) (04/13/90)

Being new to the world of interprocess communications I wrote two simple test 
programs on an Apollo workstation running Apollo's version of BSD4.3. The
first program, the server, opens a stream socket and waits for a connection.  
The second program, the client, connects to the server and goes into an 
infinite loop sending a string using the write command.  The server reads the 
message and prints it to standard output.  Unfortunately after about twenty or 
so writes by the client the server begins to drop characters. Below is the
program fragments that do the actual reading and writing after the connection
has been made:

Server
*********************************
   do {
      FD_ZERO(&ready);
      FD_SET(sock,&ready);
      to.tv_sec = 5;
      if (select (sock + 1, &ready,0, 0, &to) < 0) {
         perror ("select");
         continue;
      }
      if (FD_ISSET(sock, &ready)) {
         msgsock = accept(sock, (struct sockaddr *)0, (int *)0);
         if (msgsock == -1)
            perror("accept");
         else do {   
            bzero(buf, sizeof(buf));
            if ((rval = read(msgsock, buf, sizeof(buf))) <0)
               perror("reading stream message");
            else if (rval == 0)   
               printf("ending connection\n");
            else
               printf ("-->%s\n",buf);
              /* write(msgsock,OK,sizeof(OK));*/
         } while (rval > 0);
         close(msgsock);
      } else
         printf("do something else\n");
   } while (TRUE);


Client
*********************************
   do {
     if (write(sock, DATA, sizeof(DATA)) < 0) {
        perror("writing on stream socket");
        close (sock);
     } 
   } while (TRUE);

I assume the server is not reading as fast as the client is writing. Is there
a simple way avoid the loss of characters passing through the connection?  

                                            Mike Putnam
                                            Naval Ocean Systems Center
                                            San Diego, CA 
                                       
                                                  Internet: putnam@nosc.mil
                                                  UUCP: sdcsvax!noscvax!putnam

chris@mimsy.umd.edu (Chris Torek) (04/14/90)

In article <2125@nosc.NOSC.MIL> putnam@peanuts.nosc.mil (Mike Putnam) writes:
>... opens a stream socket ... the server begins to drop characters.

Stream sockets are supposed to be reliable.  If the connection loses
characters, there is a bug in the stream socket code.  I suspect that
is not the problem, however:

>      to.tv_sec = 5;
>      if (select (sock + 1, &ready,0, 0, &to) < 0) {

(you should set to.tv_usec, and you should cast the two `0's, but this is
not the problem I see...)

(after msgsock comes back from accept)

>	  do {   
>            bzero(buf, sizeof(buf));
>            if ((rval = read(msgsock, buf, sizeof(buf))) <0)
>               perror("reading stream message");
>            else if (rval == 0)   
>               printf("ending connection\n");
>            else
>               printf ("-->%s\n",buf);
>              /* write(msgsock,OK,sizeof(OK));*/
>         } while (rval > 0);

The `printf' call is inappropriate.  If rval < sizeof(buf), we can be
sure that buf[rval] is '\0', so that the `string' is terminated and
printf() will not go chasing phantoms.  But we could have rval ==
sizeof(buf), in which case we know nothing about buf[rval] other than
that accessing this location is illegal.

Also, it is worth noting that even if rval < sizeof(buf), it is possible
that buf[i]=='\0' for 0 <= i < rval, in which case the printf() will
stop copying at that point.


>Client
>*********************************
>   do {
>     if (write(sock, DATA, sizeof(DATA)) < 0) {
>        perror("writing on stream socket");
>        close (sock);
>     } 
>   } while (TRUE);

There may be no guarantee that write() will return sizeof(DATA): you
may be writing 1 <= n <= sizeof(DATA) bytes in some calls.  (4BSD TCP
stream sockets, except in non-blocking mode, will always return either
sizeof(DATA) or -1, except perhaps in the presence of signals.  This
is not necessarily true of other implementations.)  As with read()
loops, technically you need something like

	do {
		char *p = DATA;
		int n = sizeof DATA;
		while (n > 0) {
			int ret = write(sock, p, n);
			if (ret < 0) {
				perror("write");
				close(sock);
				sock = -1;
				break;
			}
			if (ret == 0)
				panic("ret == 0");
			p += ret;
			n -= ret;
		}
	} while (sock >= 0);
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@cs.umd.edu	Path:	uunet!mimsy!chris