Yu Cheng (Jade) ICS 451 Exercise 1 January 21, 2009 [Telnet Exercise] Use telnet to connect to the daytime port of a variety of hosts. The command (on Unix/Linux) is "telnet hostname daytime". Connect to each of the following hosts: * www.soest.hawaii.edu * mauicc.hawaii.edu * cs.berkeley.edu * nist1.symmetricom.com Did you get the same time from each one? If not, explain the difference. A: No, they are different. -------------------------------------------------------------------------------- * www.soest.hawaii.edu: Wed Jan 14 21:52:57 2009 * mauicc.hawaii.edu: Wednesday, January 14, 2009 10:07:39PM-HST * cs.berkeley.edu: Wed Jan 14 23:54:48 2009 * nist1.symmetricom.com: 54846 09-01-15 07:55:19 00 0 0 414.3 UTC(NIST) * -------------------------------------------------------------------------------- Because they are at differet time zone. What happens if you attempt to connect to the daytime port of www2.hawaii.edu? -------------------------------------------------------------------------------- Connecting To www2.hawaii.edu...Could not open connection to the host, on port d aytime: Connect failed -------------------------------------------------------------------------------- You can use telnet to connect to port 80 of a machine that is running a web server. -------------------------------------------------------------------------------- bash-2.03$ telnet www.hawaii.edu 80 Trying 128.171.224.100... Connected to web00.its.hawaii.edu. Escape character is '^]'. GET / HTTP/1.1 Host: www.hawaii.edu Accept: */* -------------------------------------------------------------------------------- I received the page contents of www.hawaii.edu. [Ping Exercise] -------------------------------------------------------------------------------- I used this site to calculte the straight distance of places. http://www.daftlogic.com/projects-google-maps-distance-calculator.htm * www2.hawaii.edu: 1.5 km => 0.005 ms * 2 = 0.01 ms 64 bytes from pwb01-2.its.hawaii.edu (128.171.94.193): icmp_seq=1. time=0. ms * mauicc.hawaii.edu: 92 km => 0.307 ms * 2 = 0.61 ms 64 bytes from mauicc.hawaii.edu (166.122.60.134): icmp_seq=1. time=4. ms * cs.berkeley.edu: 3876 km => 12.92 ms * 2 = 16 ms 64 bytes from mx1.EECS.Berkeley.EDU (169.229.60.161): icmp_seq=1. time=70. ms * www.uchicago.edu: 4255 km => 14.18 ms * 2 = 28 ms 64 bytes from uchicago.edu (128.135.13.114): icmp_seq=3. time=103. ms * www.princeton.edu: 7944 km => 26.48 ms * 2 = 53 ms 64 bytes from Princeton.EDU (128.112.128.81): icmp_seq=2. time=133. ms * nist1.symmetricom.com: 64 bytes from nist1.symmetricom.com (69.25.96.13): icmp_seq=4. time=59. ms -------------------------------------------------------------------------------- I observed that the farther the phisical distance is the longer it takes. But the actual time is longer than the estimated time. "Ping does not estimate the round-trip time, as it does not factor in the user's connection speed, but instead is used to record any packet loss, and print a statistical summary when finished." -- Wikipedia [Traceroute Exercise] -------------------------------------------------------------------------------- * www2.hawaii.edu: 2 hops * mauicc.hawaii.edu: 7 hops * cs.berkeley.edu: 14 hops * www.uchicago.edu: 12 hops * www.princeton.edu: over 30 hops * nist1.symmetricom.com: over 30 hops -------------------------------------------------------------------------------- [Unix client Exercise] Question 1: Reading data I added the following code in the client.c file to print out the response from the server. This function is called after sending the user input string and before closing the socket. -------------------------------------------------------------------------------- static void print_response(int s) { char ch; do { // Read a character from the socket and check for an error. if (1 != recv(s, &ch, 1, 0)) break; // Print the character. printf("%c", ch); // Loop over one line of data. } while (ch != '\n'); printf("\n"); } -------------------------------------------------------------------------------- Question 2: Change host and port I changed the portnumber to 13, which is the daytime port number. I modified the client code to take in two argument line inputs. The first one is the host address, and the second one is the number of connections to make. The client prints out the first and last server responses. Attached below is the modified client code. -------------------------------------------------------------------------------- : // The port number the server is listening on. #define portnumber 13 : int main(int argc, const char * argv[]) { int s; // socket descriptor struct protoent * protocolentry; struct hostent * hostentry; struct sockaddr_in sin; struct sockaddr * sap; int i; int times; if (argc != 3) { fprintf(stderr, "usage: client host iterations\n"); return EXIT_FAILURE; } // Reinterpret the sockaddr_in as a sockaddr. sap = (struct sockaddr *)&sin; // Check if the TCP protocol is available. protocolentry = getprotobyname("tcp"); if (protocolentry == NULL) error("getprotobyname"); if (sscanf(argv[2], "%d", ×) != 1) { fprintf(stderr, "%s is invalid input.\n", argv[2]); return EXIT_FAILURE; } // Get the IP address for a specified name and check for errors. hostentry = gethostbyname(argv[1]); if (hostentry == NULL || hostentry->h_addr_list == NULL) error("gethostbyname"); // Set all bytes in sockaddr_in to zero. memset(&sin, 0, sizeof(sin)); // Set the address family, port number, and IP address. sin.sin_family = AF_INET; sin.sin_port = htons(portnumber); memcpy(&sin.sin_addr, hostentry->h_addr_list[0], hostentry->h_length); for(i = 0; i < times; i++) { // Create the socket descriptor and check for an error. s = socket(AF_INET, SOCK_STREAM, protocolentry->p_proto); if (s < 0) error("socket"); // Connect to the server and check for an error. if (connect(s, sap, sizeof(sin)) < 0) error("connect"); if (i == 0 || i == times - 1) print_response(s); // Close the connection and check for an error. if (close(s) < 0) error("close"); } return EXIT_SUCCESS; } -------------------------------------------------------------------------------- Question 3: Compute the time per connection Then I used cs.berkeley.edu as the daytime server. (They might not like it...) Then I tried to make 1000 connections. -------------------------------------------------------------------------------- bash-2.03$ ./client cs.berkeley.edu 1000 Sun Jan 18 17:37:32 2009 Sun Jan 18 17:38:42 2009 -------------------------------------------------------------------------------- I used a stopwatch to time this procedure for a couple times. It took 1 min 11 secs. So the average time for building and closing a connection is about 71 ms. [Unix server Exercise] I got "bind: Address already in use" message. I need to kill the previous process before starting a new one. -------------------------------------------------------------------------------- bash-2.03$ ./server & [1] 24792 bash-2.03$ ./server & [2] 24795 bash-2.03$ bind: Address already in use -------------------------------------------------------------------------------- Question 1: Using Telnet to test your server I changed the port number that the server listens on to 15000. I telneted into the server and entered a string "hello, world!". -------------------------------------------------------------------------------- $ telnet uhunix.its.hawaii.edu 15000 (hello, world!) !dlrow ,olleh Connection to host lost. -------------------------------------------------------------------------------- [Question Section] 1: Where does the program fail if the port is in use? A: Program fails when it trying to bind. -------------------------------------------------------------------------------- : // Reserve the port and check for an error. if (bind(passive, sap, sizeof(sin)) != 0) error("bind"); : -------------------------------------------------------------------------------- 2-1: What does the "fork" command do? A: It starts another process (B) with the same running state as the process that started it (A). The fork function returns zero to process B, and it returns the process id of B (a none-zero value) to process A. 2-1: Can you modify the program to remove "fork" and have a server that only handles one connection at a time? A: I modified the server code. Basically, just commented out the fork function call and the exit statement. For my example, it sents back txt "text..." for each connection. -------------------------------------------------------------------------------- while ((session = accept(passive, sap, &adrsize)) >= 0) { if (send(session, "test...", 7, 0) < 0) error("write"); //Close the connection. if (close(session) < 0) error("child close"); } -------------------------------------------------------------------------------- bash-2.03$ ./server & [1] 8091 bash-2.03$ ./client localhost 4 test... test... test... test... -------------------------------------------------------------------------------- 2-3: See what happens if you try to connect another client while the server is connected to the first client. A: First I tested the server code with the fork operation. I ran the server and client (1). Client 1 prompted the user input. I put it in background and started another client (2). Client 2 prompted the user input. I typed "jade". I got "edaj" back. Then I put Client 1 foreground and entered "hello". I got back "olleh". So, both of client 1 and 2 were connected to the server at the same time. -------------------------------------------------------------------------------- bash-2.03$ ./server & ===> start the server [1] 10680 bash-2.03$ ./client localhost 1 ===> start client 1 enter a string: ^Z [2]+ Stopped ./client localhost 1 bash-2.03$ bg [2]+ ./client localhost 1 & [2]+ Stopped ./client localhost 1 bash-2.03$ ./client localhost 1 ===> start client 2 enter a string: jade edaj ===> response from the server bash-2.03$ jobs [1]- Running ./server & [2]+ Stopped ./client localhost 1 bash-2.03$ fg ./client localhost 1 hello olleh ===> response from the server -------------------------------------------------------------------------------- Then I tested the server code without the fork operation. I ran the server and client (1). Client 1 prompted the user input. I put it in background and started another client (2). Client 2 prompted the user input. I typed "jade". program waited forever. So, the second client was waiting to connect to the server. Multiple clients can't connect at the same time. -------------------------------------------------------------------------------- bash-2.03$ ./server & ===> start the server [1] 10745 bash-2.03$ ./client localhost 1 ===> start client 1 enter a string: ^Z [2]+ Stopped ./client localhost 1 bash-2.03$ bg [2]+ ./client localhost 1 & [2]+ Stopped ./client localhost 1 bash-2.03$ ./client localhost 1 ===> start client 2 enter a string: jade ===> waits forever... -------------------------------------------------------------------------------- 3-1: C has two ways of representing strings: null-terminated and length-based. Which way is used by the "read" and "write" or "recv" and "send" system calls? A: These system calls use lenth-based way to represent strings. 3-2: Which way is used by "strlen" and "strcpy"? A: They use null-terminated way to represent strings. 3-3: Would it be a good idea to use "printf ("%s\n", buf);" with the result of reading the data? Why or why not? A: No, it's not, unless we purposefully put a '\0' at the end of the buffer because printf("%s\n", buf) looks for the null-terminater as the end of the buf. It might go into the following memory space and prints out more than we need.