Newsgroups: comp.unix.programmer
Subject: TCP reliability
From: droux@hei.unige.ch
Date: 4 Sep 92 16:35:05 +0200
Organization: University of Geneva, Switzerland
Nntp-Posting-User: droux


TCP/IP BERKELEY SOCKETS: Transmission problems with doublicated packets
-----------------------------------------------------------------------

We are currently implementing a distributed system providing the use of
different computers (different UNIX workstations) connected by Internet.
Our System is based on a server - client model using berkeley sockets.

These two entities are communicating through AF_INET family
sockets of SOCK_STREAM type. Our Problem is, that a receiver implemented on
a NeXT receives much more packets than the sender implemented on 
a Sun workstation sends (1.3 : 1).

As TCP is known as sequenced, reliable and two-way connection based, this
fact is surprising to us. Is it possible to avoid this ? 

We implemented the mechanism as follows:

OPERATING SYSTEMS:

NeXT Cube (System Release 2.1) and SUN Sparcstation 1+ (Sun OS 4.1)

CONNECTION:

a)Server side:
  
  if ((socket_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)  /* create sockets */
    err_sys("client: error during socket creation");
  our_bzero((char *) &sock_addr,sizeof(sock_addr));
  sock_addr.sin_family = AF_INET;           /* initializes socket addresses */ 
  sock_addr.sin_port = 0;
  sock_addr.sin_addr.s_addr = INADDR_ANY;
  servlen = sizeof(struct sockaddr_in);
  if (bind(socket_fd, (struct sockaddr *)&sock_addr, servlen))
    err_sys("inet_bind_fix: error binding socket");
  if (getsockname(socket_fd, (struct sockaddr *)&sock_addr, &servlen))
    err_sys("inet_bind_fix: error getting socket name");
    
The port number is transferred using inetd to the client.

b)Client side:

  if ((socket_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)  /* create sockets */
    err_sys("client: error during socket creation");
  if ((foreign_addr = gethostbyname(machine)) == 0)       /* get the server */
    err_sys("unknown host");
  our_bzero((char *) &sock_addr, servlen);
  copy_struct(foreign_addr->h_addr,&sock_addr.sin_addr,
	foreign_addr->h_length);
  sock_addr.sin_family = AF_INET;
  sock_addr.sin_port = htons(port);
  do
  {                                          /* connect to the power server */
    connect_status = connect(socket_fd,
      (struct sockaddr *)&sock_addr, servlen);  
    connect_retries--;
  } while((connect_status < 0) && (connect_retries));
    
SOCKET OPTIONS:

#define SOCKET_BUFFER_LEN 10000                 /* buffer size of a channel */

  int buf_len = SOCKET_BUFFER_LEN;         /* set new socket buffers length */
  
  if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, 
                 (char *)&buf_len, sizeof(buf_len)) == -1)
    err_sys("set_sock_buf: cannot set new socket buffer length");
  if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, 
                 (char *)&buf_len, sizeof(buf_len)) == -1)
    err_sys("set_sock_buf: cannot set new socket buffer length");

The data exchange is made by normal read() and write() calls followed by an 
acknowledgement. We transmitt packets of 5000 bytes of unstructered data.
If a sender send 300 packets (as a concrete example) the receiver receives
over 400 packets and about 120 of them are invalid. We consider this as a
serious problem since our system is based on realibility of TCP sockets.
Is there a special option on sockets or another method to avoid these
problems?

Special Comments:
1. If the server and the client are running on the same computer, the problem
   does not occur.
2. If the NeXT (receiver client) is swapping the number of faulty packets is
   increasing.
3. The number of faulty packets is somehow depending on their size.

We would be very happy about some information as our application is part
of our graduation thesis.

Nicolas Droux & Daniel Liebhart
Biel School of Engineering, Switzerland
Computer Science Dpt.
E-mail: droux@hei.unige.ch
   
Newsgroups: comp.unix.programmer