Lecture Notes for Client-Server Interfaces

21 March 2002 - Concurrency and Processor Performance


The Objectives


The Environment


The Client

static void tcp_echo(
  char * host, char * service, unsigned size, unsigned iters) {

  char * str = new char[size];
  char * bfr = new char[size];

  for (unsigned i = 0; i < iters; i++) {

    gettimeofday(&start, NULL);

    int s = tcp_connect(host, service);

    write(s, str, size);
    tcp_read(s, bfr, size);

    shutdown(s, 1);
    close(s);

    gettimeofday(&stop, NULL);
    }
  }


An Iterative Server

const unsigned buffer_size = 1024*16;
static char buffer[buffer_size];

static void echo(int s) {

  int cc;

  do {
    cc = read(s, buffer, sizeof(buffer));
    write(s, buffer, cc);
    }
  while (cc > 0);
  }


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

  const int ms = passive_tcp(opts['s'], tcp_qlen);

  while (true) {
    const int s = accept_tcp(ms);
    echo(s);
    close(s);
    }

  return EXIT_SUCCESS;
  }


The Results


Comments


A Forking Server

const unsigned buffer_size = 1024*16;
static char buffer[buffer_size];

static void echo(int s) {

  int cc;

  while ((cc = read(s, buffer, sizeof(buffer))) > 0)
    write(s, buffer, cc);

  close(s);
  }


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

  const int ms = passive_tcp(opts['s'], tcp_qlen);

  if (signal(SIGCHLD, SIG_IGN) == SIG_ERR)
    errexit("signal(sigchld) failed:");

  while (true) {
    int ss = accept_tcp(ms);

    switch (fork()) {
      case 0:
        (void) close(ms);
        echo(ss);
        return EXIT_SUCCESS;
      default:
        (void) close(ss);
        break;
      }
    }

  return EXIT_SUCCESS;
  }


The Results


Comments


A Threaded Server

static void * echo(void * arg) {

  const int s = (int) arg;
  const unsigned buffer_size = 1024*16;
  char * buffer = new char[buffer_size];
  int cc;

  while ((cc = read(s, buffer, buffer_size)) > 0)
    write(s, buffer, cc) < 0)

  close(s);
  delete [] buffer;

  return 0;
  }

#define create_pthread(_t, _a, _f, _v) \
  do { const int e = pthread_create(&(_t), &(_a), \
                     reinterpret_cast(_f), \
                     reinterpret_cast(_v)); \
       if (e) errexit("%d = pthread_create(%s) failed:", e, #_f); \
     } while (false)

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

  const int ms = passive_tcp(opts['s'], tcp_qlen);

  pthread_t th;
  pthread_attr_t ta;
  (void) pthread_attr_init(&ta);
  (void) pthread_attr_setdetachstate(&ta, PTHREAD_CREATE_DETACHED);

  while (true)
    create_pthread(th, ta, echo, accept_tcp(ms));

  return EXIT_SUCCESS;
  }


The Results


Comments


An Event-Driven Server

const unsigned buffer_size = 1024*16;
static char buffer[buffer_size];

static int echo(int s) {

  const int cc = read(s, buffer, sizeof(buffer));
  write(s, buffer, cc);

  return cc;
  }


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

  const int ms = passive_tcp(opts['s'], tcp_qlen);

  const int nfds = getdtablesize();
  fd_set rfds, afds;
  FD_ZERO(&afds);
  FD_SET(ms, &afds);

  while (true) {
    memcpy(&rfds, &afds, sizeof(rfds));

    const int e =
      select(nfds, &rfds, NULL, NULL, (struct timeval *) 0);
    if (e < 0) errexit("select() error:");

    if (FD_ISSET(ms, &rfds)) {
      int s = accept_tcp(ms);
      FD_SET(s, &afds);
      }

    for (int fd = 0; fd < nfds; fd++)
      if ((fd != ms) && (FD_ISSET(fd, &rfds)))
        if (!echo(fd)) {
          (void) close(fd);
          FD_CLR(fd, &afds);
        }
    }

  return EXIT_SUCCESS;
  }


The Results


Comments


This page last modified on 16 March 2002.