Assignment 4

Due Monday October 30, 2017 via sakai

Introduction

You often come across advice recommending the use of fewer long packets over many short packets, or advocating the use of UDP over TCP because it is more efficient. This is a short programming assignment to understand networking performance and find the answers to these questions for your environment.

Project

Your project is to write a test program that will measure the time to transfer 1 GB of data under various conditions and prepare a report that charts the results. This is not a long or complex assignment. Your code will be shorter than this writeup. However, start early in case you run into problems.

Languages and Systems

You many use Java, C, C++, Go, or Python for this assignment. Your assignment will likely run on any system but you should make sure that it runs on the Linux systems in the iLab environment.

Groups

You may do this assignment yourself or work in a group comprising no more than three members. Your work will be held to a higher standard if working in a group.

Specifications

Your program should allow you to adjust three parameters for testing:

  1. Transport: TCP or UDP
  2. Message size: ranging from 1 byte to 65,536 bytes, incrementing in powers of two (1, 2, 4, 8, 16, …)
  3. Acknowledgements: pure streaming or stop-and-wait

All of these should be specified on the command line so you can easily modify them within a shell script.

Your program will support two modes of communication between client and server: pure streaming and a stop-and-wait protocol.

Pure streaming

Pure streaming follows the logic of (in pseudocode):

Client:

1G = 2^30
1M = 2^20
need_ack, msg_size = read_from_cmd_line()
startmsg = { need_ack=0, total_size=1G }
send(startmsg)
count = total_size
start_time = start_timer()
while (count > 0)
    bytes_sent = send(buffer, msg_size)
    if (bytes_sent != msg_size)
        error()
    count -= bytes_sent 
stop_time = stop_timer()
print (stop_time - start_time)/1M   # throughput in megabytes per second

Server:

ack, size = read()
send(ackbuf, 1)
while (buf, bytes_read = read())
    count += bytes_read
    if (count >= expected_size)
        break

Stop-and-wait protocol

A stop-and-wait protocol is one where each message is explicitly acknowledged by the client before the next message is sent. The logic is (again in pseudocode):

Client:

1G = 2^30
1M = 2^20
need_ack, msg_size = read_from_cmd_line()
startmsg = { need_ack=1, total_size=1G }
send(startmsg)
count = total_size
start_time = start_timer()
while (count > 0)
    bytes_sent = send(buffer, msg_size)
    if (bytes_sent != msg_size)
        error()
    count -= bytes_sent 
    ack, bytes_read = read()
stop_time = stop_timer()
print (stop_time - start_time)/1M   # throughput in megabytes per second

Server:

startmsg, size = read();
while (buf, size = read())
    count += size
    send(ackbuf, 1);
    if (count >= expected_size)
        break

Client

Your client will accept command-line parameters that include:

  1. Hostname (or IP address in decimal dot notation) of server
  2. Port number of server
  3. Transport protocol: TCP or UDP
  4. Acknowledgement protocol: streaming or stop-and-wait
  5. Message size

The server must be started first, of course, and will receive messages from the client. Prior to starting the data transfer, the client sends a message to the server with a message that, at a minimum, identifies the number of bytes that it will transfer. See the server section for possible extensions. It then waits for an acknowledgement from the server. This acknowledgement can be a single byte.

Prior to transferring the data, you will note the start time. After the last message was sent, you will note the end time to compute the overall elapsed time.

Basic server

Your server will be given the following parameters on the command line:

  1. Port number for requests
  2. Transport protocol: TCP or UDP
  3. Acknowledgement protocol: streaming or stop-and-wait

The server will start up, create a socket, and read messages from the client. The first message will contain the size. This can be assumed to be a fixed number of bytes (e.g., four bytes). This message is acknowledged (e.g., send back a single byte containing a 1 or whatever). Subsequent bytes read will contain the data.

The server will continue reading the data until all the bytes have been consumed or an error occurs.

Better servers

A problem with the basic server is that you need to restart it each time you restart the client. You can make your server smarter by having the client communicate some more information.

The command line accepts:

  1. Port number for requests
  2. Transport protocol: TCP or UDP

The client, in its initial message, will identify the acknowledgement protocol to be used.

You can make the server even smarter by omitting the need to specify a transport protocol and have the server create two threads, each of which is responsible for one protocol. This will take a bit more work but save you some time in running your tests.

Output

Server

At the end of each server session (when the maximum number of bytes has been read or a TCP connection has been closed) the server will print:

  • Acknowledgement protocol used
  • Number of messages read
  • Number of bytes read

Client

At the end of execution, the client will print

  • Number of messages sent
  • Number of bytes sent
  • Total transmit time

Presentation

You must run your programs on different systems to avoid using a local loopback driver. You will use your programs to create four charts:

  1. TCP performance using streaming (no acks). The x-axis will list values from 1 through 65536 scaled along log base 2 (1, 2, 4, 8, 16, …). The y axis will list the throughput in megabytes per second.

  2. TCP performance using a stop-and-wait protocol.

  3. UDP performance using streaming (no acks).

  4. UDP performance using a stop-and-wait protocol.

Important notes

  1. The number of messages sent by the server may not always equal the number of messages read by the client. TCP sockets do not have a concept of message boundaries; it’s just a byte stream.

  2. At some point, your UDP sends will fail. TCP treats a socket like a byte stream. UDP, however preserves message boundaries. If you try to send a message that exceeds the MTU (maximum transmission unit; the largest size packet that the data link layer permits), it will fail.

  3. Do not create a big file and try to transmit that. The contents don’t matter here. Just create a static buffer that’s big enough (64 KB) and use that.

  4. Make sure you are sending bytes. Do not use higher-level functions that assume you are writing strings.

  5. Help with sockets? Bing is your friend. There are tons of resources out there:

Note that SOCK_STREAM, used by the socket system call in POSIX system and exposed in Python refers to TCP sockets.

Submission

Your submission will contain:

  • Your name and the name of each group member.
  • Client code
  • Server code
  • A document (pdf or plain text) that includes:
    • CLEAR instructions on how to compile and use the programs. Do not assume the presence of any IDEs (e.g., Eclipse). Try the instructions on your non-technical friends to make sure that you didn’t miss any steps. If we have to struggle to figure out how to build or use your code, you will lose a lot of credit.
    • Usage instructions for the client and server, specifying what options are needed.
    • A brief writeup of your server design and what features you implemented.
    • Your four graphs, clearly indicating where messages failed (if that happened).

Only one group member should submit the assignment.