Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 29 Jun 1998 22:40:20 -0400 (EDT)
From:      Yee Man Chan <ymc@eecs.umich.edu>
To:        freebsd-hackers@FreeBSD.ORG
Subject:   client-server problem  
Message-ID:  <Pine.GSO.3.96.980629221622.1437A-300000@shivam.eecs.umich.edu>

index | next in thread | raw e-mail

[-- Attachment #1 --]
Hi,

	I wrote a simple client-server program (attached). What it does
is:

1. Client sends a string of n (n is a parameter) bytes
2. Server receives the string and sends the bytes it received back to the
client.

Usage:
Run server -n 100 in one shell and client -n 100 in the other shell. Then
the n mentioned above will be set to 100. The program assumes both client
and server are on the same machine, so nothing should go to the network.



Here is how the program performs under FreeBSD 3.0-CURRENT with different
n: 
1-100 Very fast
101-207 Very Slow (This range is the strangest I've ever seen)
208-1024 Very fast (just like 1-100)
>1024 strange errors like unknown host or connection timedout

Any clue?

Yee Man

[-- Attachment #2 --]
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <netdb.h>
#include <errno.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>


#ifndef BUFSIZ
#define BUFSIZ 4096
#endif

#ifndef TRUE 
#define TRUE 1
#endif

#ifndef FALSE
#define FALSE 0
#endif

#define SMALLBUF 80

#define DEFAULT_PORT 4898
#define NASA_FORMAT "%[^ ] - - \[%[^]]] \"%s %s %[^\"]\" %d %d" 
#define NASA_TIME_FORMAT "%[^/]/%[^/]/%[^:]:%[^:]:%[^:]:%[^ ] %s" 
const char * TwelveMonth[] = 
{
  "Jan",
  "Feb",
  "Mar",
  "Apr",
  "May",
  "Jun",
  "Jul",
  "Aug",
  "Sep",
  "Oct",
  "Nov",
  "Dec"
};

int errno;

/* Local functions */
static int client_comm_connect(int sock, char *dest_host, u_short dest_port);
static int tvSubUsec(struct timeval t1, struct timeval t2);
static void usage(const char *progname);

static void
usage(const char *progname)
{
  fprintf(stderr,
	  "Usage: %s [-ed] [-i Iter] [-h host] [-p port]\n"
	  "Options:\n"
	  "    -e         print replies from server (default=on).\n"
	  "    -d         setsockopt(..., TCP_NODELAY ,...).\n"
	  "    -i Iter    # of requests issued (default = 1000).\n"
	  "    -h host    Retrieve URL from cache on hostname.  Default is localhost.\n"
	  "    -p port    Port number of cache.  Default is %d.\n",
	  progname, DEFAULT_PORT);
  exit(1);
}

int
main(int argc, char *argv[])
{
  char hostname[SMALLBUF] = "localhost"; 
  char buf[BUFSIZ];
  char msg[2]="a"; /* msg[0] = cRequests % 256 is the character to be sent */
  char c;

  int port = DEFAULT_PORT;
  int itr = 1000; /* # of requests per trial */
  int conn; /* client socket id */
  int to_stdout = 1; /* print replies from server */
  int i,j;
  int cRequests;
  int usTotalResponseTime;
  struct timeval tvRequestTime, tvReplyTime;
  int bytesWritten;
  int cch;
  int tcp_nodelay = 0; /* enable Nagle's algorithm by default */
  int bytesToSend;

  /* parse all options */
  while ((c = getopt(argc, argv, "di:h:n:p")) != -1)
    switch (c) {
    case 'h':		/* host:arg */
      if (optarg != NULL)
	strcpy(hostname, optarg);
      break;
    case 'd':    /* disable Nagle's algorithm */
      tcp_nodelay = 1;
      break;
    case 'n':
      bytesToSend = atoi(optarg);
      break;
    case 'p':		/* cache port number */
      sscanf(optarg, "%d", &port);
      if (port < 1)
	port = DEFAULT_PORT;	/* default */
      break;
    case 'i':		/* # of requests to be sent */
      itr = atoi(optarg);
      break;
    case '?':		/* usage */
    default:
      usage(argv[0]);
      break;
    }

  	cRequests = 0;



	usTotalResponseTime = 0;
	for (i = 0; i < itr; i++) {

	  /* Connect to the cache server */
	  if ((conn = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
	    perror("client: socket");
	    exit(1);
	  }

	  if (tcp_nodelay) 
	    if (setsockopt(conn, IPPROTO_TCP, TCP_NODELAY, (char *) &tcp_nodelay, sizeof(tcp_nodelay)) < 0) {
	      perror(msg);
	      exit(1);
	    }
  
	  while (client_comm_connect(conn, hostname, port) < 0) {
	    perror("connect error");
	    if (errno == 0) {
	      fprintf(stderr, "client: ERROR: Cannot connect to %s:%d: Host unknown.\n", hostname, port);
	      /*
	    } else {
	      sprintf(msg, "client: ERROR: Cannot connect to %s:%d",
		      hostname, port);
	      perror(msg);
	      */	    

	    exit(1);
	    }
	    else if (errno == ECONNREFUSED) {
	      close(conn);
	      if ((conn = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
		perror("client: socket");
		exit(1);
	      }
	    }
	  }
	  
  if (bytesToSend <= 0) {
    printf("Please supply the # of bytes you expect to send per trial.\n");
    exit(1);
  }
  for (j = 0; j < bytesToSend; ++j)
    msg[j] = '0' + (j % 10);

  msg[bytesToSend] = NULL;

	  /* set RequestTimer) */
	  gettimeofday(&tvRequestTime, NULL);
	  
	  /* Send the HTTP request to the cache server */
	  bytesWritten = write(conn, msg, strlen(msg));
	    
	  if (bytesWritten < 0) {
	    perror("client: ERROR: write");
	    exit(1);
	  } else if (bytesWritten != strlen(msg)) {
	    fprintf(stderr, "client: ERROR: Cannot send request?: %s\n", msg);
	    exit(1);
	  }

	  /* Read the data */
	  while ((cch = read(conn, buf, strlen(msg))) > 0);
	  printf("%s from server\n", buf);
	  
	  /* set ReplyTimer) */
	  gettimeofday(&tvReplyTime, NULL);
	  cRequests = tvSubUsec(tvRequestTime, tvReplyTime);
	  usTotalResponseTime += cRequests;
	  
	  (void) close(conn);		/* done with socket */
	
	fprintf(stderr, "%8.5f\n", (float) cRequests/1e6);
	}

  fprintf(stderr, "Average Response Time %8.5f seconds\n", 
	  (float) usTotalResponseTime/(itr * 1e6));
  if (tcp_nodelay)
      printf("Disabled Nagle's algorithm.\n");
  exit(0);
  return 0;
}


/*
  - client_comm_connect
  -
  * Connects to the cache server
  *
  * sock   socket opened by client
  * dest_host   hostname of the destination cache server 
  * dest_port   port of the dest_host to which to connect 
  *
  * returns -1 if an error occurs 0 otherwise
  * connect returns 0 on no error 
  */ 
static int
client_comm_connect(int sock, char *dest_host, u_short dest_port)
{
  const struct hostent *hp;
  static struct sockaddr_in to_addr;
  
  /* Set up the destination socket address for message to send to. */
  to_addr.sin_family = AF_INET;
  
  if ((hp = gethostbyname(dest_host)) == 0) {
    return (-1);
  }
  memcpy(&to_addr.sin_addr, hp->h_addr, hp->h_length);
  to_addr.sin_port = htons(dest_port);
  return connect(sock, (struct sockaddr *) &to_addr, sizeof(struct sockaddr_in));
}

static int
tvSubUsec(struct timeval t1, struct timeval t2)
{
    return (t2.tv_sec - t1.tv_sec) * 1000000 +
        (t2.tv_usec - t1.tv_usec);
}

[-- Attachment #3 --]
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <signal.h>
#include <fcntl.h>
#include <ctype.h>
#include <unistd.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>

#define TIN_PORT 4898

int tind_args(int argc, char *argv[], int *port, int * bytes);
char * selectANDread(int td, char *buf, int blen);
void tind_usage(char *progname);

int errno;

int main(int argc, char * argv[]) {

  int rd, conn, reuse, len, port;
  struct sockaddr_in self, client;
  char buf[2048];
  int flags;
  int bytesToReceive = 0;

  /* option parsing */
  if (tind_args(argc, argv, &port, &bytesToReceive)) {
    tind_usage(argv[0]);
  }

  if (bytesToReceive <= 0) {
    printf("Please supply the # of bytes you expect to receive per trial.\n");
    exit(1);
  }


  while (1) {
    conn = socket(AF_INET, SOCK_STREAM, 0);
    if (conn < 0) {
      perror("Socket Error!!!\n");
      exit(1);
    }

    memset((char *) &self, 0, sizeof(struct sockaddr_in));
    self.sin_family = AF_INET;
    self.sin_addr.s_addr = INADDR_ANY;
    self.sin_port = htons((u_short) port);
    reuse = 1;
    if (setsockopt(conn, SOL_SOCKET, SO_REUSEADDR, (char *) &reuse, sizeof(int)) < 0) {
      perror("setsockopt error!!!");
      exit(1);
    }

    if (bind(conn, (struct sockaddr *) &self, sizeof(struct sockaddr_in)) < 0) {
      perror("bind error!!!");
      exit(1);
    }

    if (listen(conn, 5) < 0) {
      perror("listen error!!!");
      exit(1);
    }

v
    len = sizeof(struct sockaddr_in);

    rd = accept(conn, (struct sockaddr *) &client, &len);

    if (rd < 0) {
      perror("accept error!!!");
      exit(1);
    }

    memset(buf, 0, 2048); 
    selectANDread(rd, buf, bytesToReceive);
    printf("%s from client\n", buf);
    send(rd, buf, bytesToReceive, 0);
    close(conn);
    close(rd);
  }
}  

char *
selectANDread(int td, char *buf, int blen)
{
  int i;
  int err;
  char *bp;
  int len, left;
  char *errmsg;
  fd_set fdset;
  struct timeval timeout;
  
  FD_ZERO(&fdset);
  FD_SET(td, &fdset);
  
  timeout.tv_sec = 0;
  timeout.tv_usec = 500;
  

  /* initialize variables */
  i = 0;
  errno = 0;
  bp = buf;
  left = blen;
  errmsg = (char *) 0;

  /* poll socket for data every TIND_SLEEPUSEC
     in case client or connection is slow and
     data hasn't arrived.  But do this only
     TIND_MAXTRIES times so that buggy client
     won't put us in an infinite loop.
     Better implemented with select(). */
  do {
    len = read(td, bp, left);
    
    if (len < 0 && errno == EWOULDBLOCK) {
      i++;
      len = 1;
      errno = 0;
      if (select(td+1, &fdset, NULL, NULL, &timeout) < 0) {
        printf("Error in file %s line %d\n", __FILE__, __LINE__);
        exit(1);
      }
    } else {
      i = 0;
      bp += len;
      left -= len;
    }
  } while (len > 0 && left > 0 && i < 10);
}
  
void
tind_usage(char *progname)
{
  fprintf(stderr, "Usage: %s -p <portnum>\n", progname);
  exit(errno);
}

/*
 * tind_args: Parse args.
 *
 * Return 0 on success or errno on failure.
 * On successful return, "port" contains the
 * port# to use, in host byte order.
*/
int
tind_args(int argc, char *argv[], int *port, int * bytes)
{
  char c;
  extern int optind;
  extern char *optarg;

  errno = 0;
  *port = TIN_PORT;
  while ((c = getopt(argc, argv, "p:n:l:")) != EOF) {
    switch (c) {
    case 'p':
      *port = atoi(optarg);
      break;
    case 'n':
      *bytes = atoi(optarg);
      return 0;
    default:
      errno = EINVAL;
      break;
    }
  }

  return(errno);
}

help

Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?Pine.GSO.3.96.980629221622.1437A-300000>