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