ICS 451 Homework 1: UNIX Client and Server

Handed out January 12th, to be completed by January 19th at 3pm. Answers must be emailed to esb@hawaii.edu, and must be received by 3pm Hawaii Standard Time.

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.berkeley.edu
  3. cs.cmu.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 cs.stanford.edu?

1.b Ping

Now use ping to determine the average 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. The speed of light is 300,000 km/s, the distance to the various hosts is:

  1. www.hawaii.edu: less than 1 km
  2. cs.berkeley.edu: 3865 km
  3. cs.cmu.edu: 7500 km
  4. escher.uni-muenster.de: 12000 km
The distance figures are from Bali Online.

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, so that I have a record of your doing this. Do this as many time as desired.

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.

Note: if you get "Connection refused", the server is down. Please let the instructor know he needs to restart the server.

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 gave, in reverse order (backwards).
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.

2.e Turn in

For all of exercise 2, what you need to report is:

  1. the total time for 500 connections
  2. the time per connection.
Please do NOT turn in your code.

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, and only one program can do that at a time).

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

For Exercise 3, you need to turn in:
  1. The result of running the unix diff command with as arguments the original server and your server (again, do NOT email your entire source file).
  2. The error message that is printed when you try to run a second server.

Computer Networks, ICS 451
Instructor: Edo Biagioni