CSS 432
Program 1: Basic TCP Communication

Professor: Munehiro Fukuda
Due date: See the syllabus


1. Purpose

This assignment exercises basic TCP communication and evaluates its performance over 1Gbps networks. You are to observe how RTT (round trip time) grows as increasing the size of data to send over 1Gbps point-to-point communication.

2. Client-Server Model

In all your programming assignments through to the final project, your program will use the client-server model where a client process establishes a connection to a server, sends data or requests, and close the connection while the server sends back responses or acknowledgments to the client.

3. TCP Communication

HW1 focuses on basic TCP communication between a client and a server process. To establish such communication, those processes should perform the following sequence of operations:

Client

  1. Use argv[0] as the C string that stores a server IP name.
  2. Retrieve a hostent structure corresponding to this IP name by calling gethostname( ).
        struct hostent* host = gethostbyname( argv[1] );
    
  3. Declare a sockaddr_in structure, zero-initialize it by calling bzero, and set its data members as follows:
        int port = YOUR_ID;  // the last 5 digits of your student id
        sockaddr_in sendSockAddr;
        bzero( (char*)&sendSockAddr, sizeof( sendSockAddr ) );
        sendSockAddr.sin_family      = AF_INET; // Address Family Internet
        sendSockAddr.sin_addr.s_addr =
          inet_addr( inet_ntoa( *(struct in_addr*)*host->h_addr_list ) );
        sendSockAddr.sin_port        = htons( port );
    
  4. Open a stream-oriented socket with the Internet address family.
        int clientSd = socket( AF_INET, SOCK_STREAM, 0 );
    
  5. Set the NODELAY option. (Note this option is necessary to observe the TCP's segmentation behavior clearly in HW1. Don't use this option in the other assignments.)
        const int on = 1;
        setsockopt( clientSd, IPPROTO_TCP, TCP_NODELAY, (char *)&on, sizeof( int ) );
    
  6. Connect this socket to the server by calling connect as passing the following arguments: the socket descriptor, the sockaddr_in structure defined above, and its data size (obtained from the sizeof function).
        connect( clientSd, ( sockaddr* )&sendSockAddr, sizeof( sendSockAddr ) );
    
  7. Use the write system call to send data.
  8. Use the read system call to receive a response from the server.
  9. Close the socket by calling close.
      close( clientSd );
    

Server

  1. Declare a sockaddr_in structure, zero-initialize it by calling bzero, and set its data members as follows:
        int port = YOUR_ID;  // the last 5 digits of your student id
        sockaddr_in acceptSockAddr;
        bzero( (char*)&acceptSockAddr, sizeof( acceptSockAddr ) );
        acceptSockAddr.sin_family      = AF_INET; // Address Family Internet
        acceptSockAddr.sin_addr.s_addr = htonl( INADDR_ANY );
        acceptSockAddr.sin_port        = htons( port );
    
  2. Open a stream-oriented socket with the Internet address family.
        int serverSd = socket( AF_INET, SOCK_STREAM, 0 );
    
  3. Set the NODELAY option. (Note this option is necessary to observe the TCP's segmentation behavior clearly in HW1. Don't use this option in the other assignments.)
        const int on = 1;
        setsockopt( serverSd, IPPROTO_TCP, TCP_NODELAY, (char *)&on, sizeof( int ) );
    
  4. Bind this socket to its local address by calling bind as passing the following arguments: the socket descriptor, the sockaddr_in structure defined above, and its data size.
        bind( serverSd, ( sockaddr* )&acceptSockAddr, sizeof( acceptSockAddr ) );
    
  5. Instructs the operating system to listen to up to five connection requests from clients at a time by calling listen.
        listen( serverSd, 5 );
    
  6. Receive a request from a client by calling accept that will return a new socket specific to this connection request.
        sockaddr_in newSockAddr;
        socklen_t newSockAddrSize = sizeof( newSockAddr );
        int newSd = accept( serverSd, ( sockaddr *)&newSockAddr, &newSockAddrSize );
    
  7. Use the read system call to receive data from the client. (Use newSd but not serverSd in the above code example.)
  8. Use the write system call to send back a response to the client. (Use newSd but not serverSd in the above code example.)
  9. Close the socket by calling close.
        close( newSd );
    
You need to include the following header files so as to call these OS functions
    #include <sys/types.h>    // socket, bind
    #include <sys/socket.h>   // socket, bind, listen, inet_ntoa
    #include <netinet/in.h>   // htonl, htons, inet_ntoa
    #include <arpa/inet.h>    // inet_ntoa
    #include <netdb.h>        // gethostbyname
    #include <unistd.h>       // read, write, close
    #include <string.h>       // bzero
    #include <netinet/tcp.h>  // TCP_NODELAY

Socket.h and Socket.cpp

If you would like to take an easy-going option, you may use Socket.h and Socket.cpp that the professor has implemented in ~css432/hw1/. In this case, you don't need to include the header files listed above. However, there are few comments in these files. At least, you have to learn how to use this class. :-)

4. Statement of Work

Write a program that establishes a TCP connection from a client to a server, sends data from the client to the server as incrementing the data size, and sends back an acknowledgment from the server to the client. Your program must repeat the following iteration as changing data size from 100 bytes to 20,000 bytes by 100 bytes. For each iteration:

Client

  1. Open a new socket and establish a connection to a server.
  2. Start a timer by calling gettimeofday.
  3. Send a given size of data to the server.
  4. Receive a one-byte acknowledgment from the server.
  5. Stop the timer by calling gettimeofday.
  6. Prints out the data size, a space " ", and elapsed time in usec to the standard output.
  7. Close the socket.
  8. Increment the data size by 100 bytes and go back to the top.

Server

  1. Accept a new connection. (The very first socket should be opened and bound before this iteration.)
  2. Read data from the client. Note that the read system call may return without reading the entire data if it is unavailable to read. You may have to repeat calling read like:
           for ( int nRead = 0; ( nRead += read( sd, buf, size - nRead ) ) == size; );
    
    Check the manual page for read carefully.
  3. Write a one-byte acknowledgment to the client.
  4. Close this connection.
  5. Go back to the top.
You should write only one program that should identify with argc if it is a client or a server. Your program invocation should be:
   Server Side:
      $ a.out
   Client Side:
      $ a.out serverIpName > result
where result stores all standard output messages from your a.out program. Make sure that you must start your server first. You must conduct performance evaluation over 1Gbps network. The linux machines of uw1-320-00 ~ uw1-320-15 are connected to 100Mbps Ethernet, while uw1-320-16 ~ uw1-320-31 are connected to 1Gbps Ethernet. Thus, what you have to do is
  1. Login any two of 1Gbps-connected machines and evaluate the 1Gbps performance. Store your result in the 1gbps.dat file.
       Client Side:
          $ a.out serverIpName > 1gbps.dat
    
  2. Print out those results using gnuplot. Copy the ~css432/hw1/tcp.plt file to the same directory where your result files exist, and run gnuplot tcp.plt which generates tcp.ps
         cp ~css43/hw1/tcp.plt .
         gnuplot tcp.plt
    
  3. Convert an obtained ps file in a pdf file and view it with evince. Specifically, type as follows:
         ps2pdf tcp.ps
         evince tcp.pdf
    
  4. You may have to repeat this evaluation several times until you obtain a very clear graph.

5. What to Turn in

The homework is due at the beginning of class on the due date. You have to turn in the following materials in hard copy. No email submission is accepted.
Criteria Percentage
Documentation of your algorithm including explanations and illustrations in one or two pages 2pts(10%)
Source code that adheres good modularization, coding style, and an appropriate amount of comments. The source code is graded in terms of (1) Correct tcp socket establishments, (2) correct data/ack transfers, (3) Use of gettimeday, (4) performance evaluating code, and (5) comments, etc. 5pts(25%)
Execution output such as a snapshot of your display/windows. Type import -window root X.jpeg; lpr -Puw1-320-p1 X.jpeg on a uw1-320 linux machine. Or, submit partial contents of standard output redirected to a file. You don't have to print out all data. Just one page evidence is enough. 1pts(5%)
Performance evaluation that prints out the tcp.ps (or tcp.pdf) file. (NOTE! NOTE! NOTE! your elapsed time should grow in steps rather than linearly) 6pts(30%)
Discussions should be given for 1Gbps performance in terms of MSS (1448bytes), MTU (1500bytes), socket buffers (16384bytes), the Linux page size (4096bytes), and advertized window size (the multiplicaiton of MSS). 6pts(30%)
Total 20pts(100%)

6. FAQ

This FAQ page may answer your quetions. Click here