ICS 451 Homework 1: UNIX Client and Server

Handed out August 31th, to be completed by Friday September 4th.

Read the following Unix man pages: socket(2), bind(2), listen(2). accept(2), connect(2), fork(2).

1 Existing Unix clients

1.a Telnet

Use telnet to connect to the daytime port of a variety of hosts. The command is "telnet hostname daytime". Connect to each of the following hosts:
  1. www.hawaii.edu
  2. cs.stanford.edu
  3. prep.ai.mit.edu
  4. escher.uni-muenster.de
Did you get the same date and time from each one? If not, explain the difference.

What happens if you attempt to connect to the daytime port of www.stanford.edu?

1.b Ping

Now use ping to determine the round-trip time to each of these four hosts. On the suns (including uhunix), the command is "/usr/sbin/ping". If you're not familiar with ping, use "man ping" to find out how to use the "-s" switch. Report the round-trip time for each of these hosts.

Can you justify the round-trip times to each of these hosts by considering just the speed of light? Compare (approximate) distances to delays.

2 Writing a Unix client

2.a Compiling and running

Cut and paste the following code into a file, compile it, and run it. At the prompt, enter your email address and your name.

Note that the program will not compile on uhunix, which does not have a C compiler. Send mail to sunx@hawaii.edu to obtain an account on the ICS Unix workstations, including your full name and the fact that you need an account for ICS 451.

Also note that you are welcome to do exercises 2 and 3 on winsock instead of Unix if you prefer. If you use winsock, you will have to figure out for yourself how to write a client and a server.


/* client.c: program to connect to server. */
/* compile with: gcc -o client client.c -lsocket -lnsl */

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>

#define portnumber 4321
#define BUFSIZE 1000

#define error(s) { perror(s); exit(1); }

main ()
{
  int s;
  struct protoent * protocolentry;
  struct hostent * hostentry;
  struct sockaddr_in sin;
  struct sockaddr * sap = (struct sockaddr *) &sin;
  char buf[BUFSIZE];

  if ((protocolentry = getprotobyname("tcp")) == NULL)
    error("getprotobyname");
  if ((s = socket(AF_INET, SOCK_STREAM, protocolentry->p_proto)) < 0)
    error("socket");
  hostentry = gethostbyname("maru.ics.hawaii.edu");
  if ((hostentry == NULL) || (hostentry->h_addr_list == NULL))
    error("gethostbyname");
  bzero (&sin, sizeof (sin));
  sin.sin_family = AF_INET;
  bcopy(hostentry->h_addr_list[0], &(sin.sin_addr), hostentry->h_length);
  sin.sin_port = htons(portnumber);
  if (connect(s, sap, sizeof(sin)) < 0) error("connect");
  printf ("enter your e-mail address and your name: ");
  fgets (buf, BUFSIZE, stdin);
  if (write(s, buf, strlen(buf)) < 0) error("write");
  if (close(s) < 0) error("close");
}

This program contacts a server running on the machine "maru" and gives it your name and email. These will be recorded automatically for grading.

2.b Reading data

Modify the client program to read data from the server after sending the data. The data received should be the same data you typed, reversed. Set aside a copy of this program for (3.a).

2.c Change host and port

Modify the client program in 2.b to read data from the daytime port, port 13, and from host "maru.ics.hawaii.edu". Your modified program should not write anything to the remote host.

2.d Compute the time per connection

Modify the client program to connect to the daytime port in a loop until it has connected 500 times. Then use the first and the last times returned to estimate how long it takes to establish and teardown a connection.

For all of exercise 2, the only thing you need to report is the total time and the time per connection from exercise 2.d.

3 Writing a Unix server

3.a Compiling and running

Cut and paste the following code into a file, compile it, and run it in the background. Then connect to it using your client program from (3.b). Note that you have to change the name of the host that the client connects to. Try running the client both on the same host as the server, and on a different host.

If you have trouble running the server, try using a different port number (someone else may be using the same port number as you).

Make sure you have killed your server when you are done. On the suns, use "ps -U yourlogin" to see what processes are still running.




/* server.c: program to accept input from clients. */
/* compile with: gcc -o server server.c -lsocket */

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <signal.h>

#define portnumber 4321
#define BUFSIZE 1000

#define error(s) { perror(s); exit(1); }

main ()
{
  int passive, session;
  struct sockaddr_in sin;
  struct sockaddr * sap = (struct sockaddr *) &sin;
  struct sigaction siga;
  int count, i = 0, pos = 0;
  char buf[BUFSIZE] = "";

  if ((passive = socket(AF_INET, SOCK_STREAM, 0)) < 0) error("socket");
  bzero (&sin, sizeof (sin));
  sin.sin_family = AF_INET;
  sin.sin_port = htons(portnumber);
  sin.sin_addr.s_addr = INADDR_ANY;
  if (bind(passive, sap, sizeof (sin)) != 0) error("bind");
  /* make sure child processes are really detached (see exit(2)) */
  signal(SIGCHLD, SIG_IGN);
  /* specify the maximum queue length */
  if(listen(passive, 5) < 0) error("listen");
  count = sizeof (sin);
  while ((session = accept(passive, sap, &count)) >= 0) {
    if (fork() == 0) {	/* child process */
      count = read(session, buf, BUFSIZE - 1);
      buf[count] = '\0';
      pos = count - 1;
      if (buf[pos] == '\n') pos--;
      for (i = 0; i <= pos; ) {   /* reverse string */
	int swap = buf[i];
	buf[i++] = buf[pos];
	buf[pos--] = swap;
      }
      if (write(session, buf, count) < 0) error("write");
      if (close(session) < 0) error("child close");
      exit(0);
    } else {			/* parent process */
      if (close(session) < 0) error("parent close");
    }
  }
}

3.b Bind

Note what happens if you try to run a second server while the first is still running. The operating system marks the port "in use" so that only one server can use it at a time. If a connection has been opened, the operating system may mark the port "in use" for a few minutes after the server is gone.

3.c Turn in

You do not need to turn anything in for Exercise 3 -- it will serve as a basis for project 1.

Computer Networks, ICS 451
Instructor: Edo Biagioni