A note on answers. If you do turn in the homework, please spend a little time making sure you only turn in the parts that are relevant, that is, answers to questions that the instructor asked, and questions that you may have, including any material needed to understand your questions. For this homework there is little benefit in sending me copies of the code that I posted on the web, or traceroute logs, or similar things.
What happens if you attempt to connect to the daytime port of www.berkeley.edu?
You can use telnet to connect to port 80 of a machine that is running a web server. Then, type:
GET pathBe sure to include an empty line. This should get you the HTML source code for the document specified by path. You can also type (e.g., for www.berkeley.edu)
GET / HTTP/1.1 Host: www.berkeley.edu Accept: */* Connection: close(where "/" is your path). The first request is HTTP 0.9, this one is HTTP 1.1. In HTTP 1.1, we may have one or more header fields following the initial line. Project 3 will explore this.
Can you justify the round-trip times to each of these hosts by considering just the speed of light? In other words:
If you can, also try this from your home machine, and compare and try to explain the results:
/* client.c: program to connect to server. */
/* on the suns, compile with: gcc -o client client.c -lsocket -lnsl */
/* on linux, compile with: gcc -o client client.c */
#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 /* this is where the server can be reached */
#define BUFSIZE 1000 /* we truncate strings longer than this */
#define print_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];
/* get the protocol named TCP */
if ((protocolentry = getprotobyname("tcp")) == NULL)
print_error("getprotobyname");
/* create a TCP socket */
if ((s = socket(AF_INET, SOCK_STREAM, protocolentry->p_proto)) < 0)
print_error("socket");
/* find the IP address of the server */
hostentry = gethostbyname("maru.ics.hawaii.edu");
/* always check the return value */
if ((hostentry == NULL) || (hostentry->h_addr_list == NULL))
print_error("gethostbyname");
/* initialize the socket address */
bzero (&sin, sizeof (sin));
sin.sin_family = AF_INET;
/* copy the destination IP to the socket address */
memcpy(&(sin.sin_addr), hostentry->h_addr_list[0], hostentry->h_length);
/* also set the port number in the socket address */
sin.sin_port = htons(PORTNUMBER);
/* now establish a TCP connection to the given address, referred to
by the socket we created above */
if (connect(s, sap, sizeof(sin)) < 0) print_error("connect");
/* get user data, and send it to the server */
printf ("enter a string: ");
fgets (buf, BUFSIZE, stdin);
if (write(s, buf, strlen(buf)) < 0) print_error("write");
/* close the connection (and the socket at the same time) */
if (close(s) < 0) print_error("close");
}
This program contacts a server running on the machine "maru.ics.hawaii.edu"
and gives it the string you enter.
If you are on a machine that is not a sun, you may have to use different include files or different link switches (the "-l" switches).
You are welcome (but not required) to rewrite this program to run on a Windows system. If you send it to me, I will post it here.
Save a copy of this program for later use, in part 1 of the server exercise.
/* server.c: program to accept input from clients. */
/* on suns, compile with: gcc -o server server.c -lsocket -lnsl */
/* on linux, compile with: gcc -o server server.c */
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <netinet/in.h>
#include <signal.h>
#include <netdb.h>
#define PORTNUMBER 4321
#define BUFSIZE 100
#define print_error(s) { perror(s); exit(1); }
main ()
{
int passive, session;
struct sockaddr_in sin;
struct sockaddr * sap = (struct sockaddr *) &sin;
int count, i = 0, pos = 0;
char buf[BUFSIZE] = "";
struct sigaction siga;
struct protoent * protocolentry;
if ((protocolentry = getprotobyname("tcp")) == NULL)
print_error("getprotobyname");
if ((passive = socket(PF_INET, SOCK_STREAM, protocolentry->p_proto)) < 0)
print_error("socket");
bzero (&sin, sizeof (sin));
sin.sin_family = AF_INET;
sin.sin_port = htons(PORTNUMBER);
/* connections may be to any IP address belonging to this host */
sin.sin_addr.s_addr = INADDR_ANY;
/* bind the socket to the address, to specify which port this server
is using */
if (bind(passive, sap, sizeof (sin)) != 0) print_error("bind");
/* make sure child processes are really detached (see exit(2)) */
/* note this doesn't work on Linux -- see below for Linux fix */
if (sigaction (SIGCHLD, NULL, &siga) < 0) print_error ("sigaction/get");
siga.sa_flags |= SA_NOCLDWAIT | SA_NOCLDSTOP;
if (sigaction (SIGCHLD, &siga, NULL) < 0) print_error ("sigaction");
/* specify the maximum queue length */
if(listen(passive, 5) < 0) print_error("listen");
count = sizeof (sin);
/* "accept" creates new sockets when a client connects */
while ((session = accept(passive, sap, &count)) >= 0) {
if (fork() == 0) { /* create a child process -- code follows */
/* read the client data */
count = read(session, buf, BUFSIZE - 1);
/* turn it into a C string */
buf[count] = '\0';
pos = count - 1;
/* get rid of any final newline */
if (buf[pos] == '\n') pos--;
/* just to do something, here we reverse the string
that we received and return it to the client */
for (i = 0; i <= pos; ) {
int swap = buf[i];
buf[i++] = buf[pos];
buf[pos--] = swap;
}
if (write(session, buf, count) < 0) print_error("write");
/* this child is done, can exit */
if (close(session) < 0) print_error("child close");
exit(0);
} else { /* parent process */
if (close(session) < 0) print_error("parent close");
/* on Linux, the above sigactions do not prevent child
processes from becoming zombies, so instead simply
wait(2) (without suspending) until all that are ready
to harvest are harvested. */
while (waitpid (-1, NULL, WNOHANG) != 0) {
}
}
}
}
If you have trouble running the server, someone else on the same machine may be using the same port number, so try using a different port number. Of course, the port number in the client must match the port number in the server.