Project Part 2 Solution



1. Overview:

For part 1 of the project, your team will implement a simple go-back-N protocol similar to TCP. This protocol is called the 352 Reliable Data Protocol (RDP) version 1 (352 RDP v1). You will realize it as a Python (version 3) module that uses UDP as the underlying transport protocol. Later versions will add other features like security, flow control and congestion control.

As part of the project part 1, you will be given 3 files. You can find them in the Sakai site under “Resources” -> “Project resources” -> “Part 1” .

  1. This is a skeleton definition of the class and methods you need to write. You should modify this file with your implementation. That is, fill in the methods with your own code.

  1. A Python client program that uses CS 352 sockets. You may not alter the source code for this file.

  1. Python server program that uses CS 352 sockets. You may not alter the source code for this file.

Your library must implement the following methods as defined in the file, note that some of the functions may not require you to do anything:

init(udp_port1, udp_port2)









Python Version:

I strongly recommend you use python 3. Whichever version you use you must tell us in the readme file.

These function map to the existing Python methods for sockets. See this link: the definitions of these functions. The one exception init()call. This call takes two parameters, which are the UDP port that the rest of the CS 352 RDP library will use for communication between hosts, one is for receiving and one is for sending. Setting the udp_port to zero should use the default ports of your choosing.

For part 1 of the project, you will only need to make a single connection work over a single set of ports for a single thread.The goal is to correctly implement a go-back-N protocol for one connection, for example, when sending a single file between a client and server.

Figure 1: Layering in CS 352 Sockets

2. Architecture

Figure 1 shows the architecture of the 352 socket layer. All communications go through a single UDP socket. A set of ports which are managed by 352 sockets exists on top of the UDP socket.

To allow 2 instances of 352 sockets to communicate on the same machine, 2 UDP sockets must be used, one for each instance. As these can not have the same UDP port number, they must have different port numbers. In this case, each instance must use 2 different UDP ports, one for sending and one for receiving.

3. The 352 RDP v1 protocol:

Recall as in TCP, 352 RDP v1 maps the abstraction of a logical byte stream onto a model of an unreliable packet network. 352 RDP v1 thus closely follows TCP for the underlying packet protocol. A connection has 3 phases: Set-up, data transfer, and termination. 352 RDP v1 uses a much simpler timeout strategy than TCP for handling lost packets.

Packet structure:

The CS 352 RDP v1 packet as defined as a C structure, which must be translated into a Python struct:

/* a CS 352 RDP protocol packet header */ struct

__attribute__ ((__packed__)) sock352_pkt_hdr { uint8_t


/* version number */

uint8_t flags;

/* for connection set up, tear-down, control */

uint8_t opt_ptr;

/* option type between the header and payload */

uint8_t protocol;

/* higher-level protocol */

uint16_t header_len;

/* length of the header */

uint16_t checksum;

/* checksum of the packet */

uint32_t source_port;

/* source port */

uint32_t dest_port;

/* destination port */

uint64_t sequence_no;

/* sequence number */

uint64_t ack_no;

/* acknowledgement number */

uint32_t window;


receiver advertised window in bytes*/

uint32_t payload_len; /* length of the payload */

}; typedef​ ​struct sock352_pkt_hdr sock352_pkt_hdr_t; /* typedef shortcut */

Fields in Red(version,flags,header_len,sequence_no,ack_no,payload_len) must be filled in

correctly in part 1, while the Bluefields can be ignored for this part of the project. They should still be included in the struct, but they should always hold zero.

Note that uintX_t is an X-bit unsigned integer., as defined in <sys/types.h>.At the packet level, all these fields are defined to be in network byte-order (big-endian, most significant byte first).

In Python, you will need to use the structmodule to pack and unpack binary data (see this link for a description of the struct library: ) A struct object takes a formating string and allows you to create a binary object based on the format and Python variables. This is called a packoperation. The inverse, or unpack,takes a binary object and unpacks it into a set of Python variables. Recall for the format string, B = Byte, H = Half-Word (16 bits) , L=Long (32 bits) Q=Quad (64bits), and the “!” means use network byte order. Some example code to pack a CS 352 packet header might look like this:

sock352PktHdrData = ‘!BBBBHHLLQQLL’

udpPkt_hdr_data = struct.Struct(sock352PktHdrData)

header = udpPkt_header_data.pack(version, flags, opt_ptr, protocol, checksum, source_port, dest_port, sequence_no, ack_no, window, payload_len)

For part 1, in the packet, the versionfield should be set of 0x1. The protocol, opt_ptr, source_port and dest_portfields should all be set to zero. Future versions of the protocol might add port spaces and options. The header_lenfield will always be set to the size of the header, in bytes.

An address for the CS 352 RDP is slightly different from the normal socket address, as found in the sock352.h file. The main difference is the addition of a port layer on top of the UDP port space, as seen in the cs352_portfield. This might be used in later versions of the protocol.

Connection Set-up:

352 RDP follows the same connection management protocol as TCP. See Chapter 3.5.6, pages

252-258 of Kurose and Ross for a more detailed description. The versionfield of the header should always be set to 1.


The bit flags needed are set in the flagsfield of the packet header. The exact bit definitions of the flags are:

Flag Name

Byte Value (Hex)

Byte Value (Binary)










Connection end




Acknowledgement #










Option field is valid

The client initiates a connection by sending a packet with the SYN bit set in the flagsfield, picking a random sequence number, and setting the sequence_nofield to this number. If no connection is currently open, the server responds with both the SYN and ACK bits set, picks a random number for it’s sequence_nofield and sets the ack_no field to the client’s incoming sequence_no+1.If there is an existing connection, the server responds with the sequence_no+1,but the RESET flag set.

Data exchange:

352 RDP follows a simplified Go-Back-N protocol for data exchange, as described in section Kurose and Ross., Chapter 3.4.3, pages 218-223 and extended to TCP style byte streams as described in Chapter 3.5.2, pages 233-238.

When the client sends data, if it is larger than the maximum UDP packet size (64K bytes), it is first broken up into segments, that is, parts of the application byte-stream, of up to 64K. If the client makes a call smaller than 64K, then the data is sent in a single UDP packet of that size, with the payload_lenfield set appropriately. Segments are acknowledged as the last segment received inorder (that is, go-back-N). Data is delivered to the higher level application in-order based on the recv()calls made. If you are having difficulties you can try 32k maximum packet size instead of 64k, this sometimes helps.

For CS 352 RDP version 1, the window size can be ignored, this means we are assuming the size of the window is always greater than the total amount of data to be sent.

Here is a simulation to help you understand what is going on:

Timeouts and retransmissions:

352 RDP v1 uses a single timer model of timeouts and re-transmission, similar to TCP in that there should be a single timer per connection,although each segment has a logical timeout. The timeout for a segment is 0.2 seconds. That is, if a packet has not been acknowledged after 0.2 seconds it should be re-transmitted, along with any packets sent afterwards as per go back N. The logical timeout would be set again set to 0.2 seconds in the future for that segment. The timeout used for a connection should be the timeout of the oldest segment.

There are two strategies for implementing timeouts. One approaches uses Unix signals and other uses a separate thread. These will be covered in class and recitation. I strongly recommend using a seperate thread to receive acknowledgments and keep track of timeouts and sending data on the first thread.

Connection termination:

Connection termination will follow a similar algorithm to TCP, first one side sends a message with FIN bit set, then the other side replies with FIN and ACK set, then the first side replies with ACK set.

3. Invoking the client and server:

The client and server take a number of arguments :

-f <the file name to send or to save>

-d <the destination host to send to>

-u <the UDP port to use for receiving>

-v <the UDP port to use for sending> (optional)

If you are running both the client and server on the same machine, you would, for example, in one terminal window, first run the server: -f savedFile.pdf –u 8888 –v 9999

In a second terminal window, run the client: -d localhost -f sendFile.pdf –u 9999 –v 8888

NOTE: When testing please retype the commands as copy-pasting from PDF files may work strangely

Notice how the send and receive ports are swapped. If we were running on different machines, a single UDP socket (port) could be used for both sending and receiving.

Remember to find a way to test what happens when packets are dropped and to test with files ranging from a few bytes to many megabytes.

4. New In Part 2

Since we are doing flow control, the receiver must keep a buffer of received data, every me recv is called, the specified amount of data is returned and removed from the buffer. The buffer is of size W,W=262kb for this project. If the buffer is empty and recv is called, wait until there is something to return. Alternately, if there is no more room in the buffer, send() calls by the sender should not return or send anything until there is room. This is kept track of by the widow size field of each packet as in real TCP. Whenever you send an ack, include the room in your buffer at the moment in the window feild as in real tcp. Lastly, you must send an ack when your buffer gets more room even if you did not get any packets.

Note that just like real TCP this is a sliding window protocol and you must never send more packets than will fit in the buffer.

5. Grading:

Functionality: 80% Style: 20%


We will run the client.pyprogram and the server.pyprogram on different, or possibly the same, machines. The client.pyprogram opens a single file, sends to the server, and then both close the socket and exit. See the source code for more details. They will both run on ilab machines. The size of the file may range from a few bytes to many megabytes. We will then use checksums to make sure the entire file has sent correctly. We will insert pauses into the program to make sure that you don’t send packets when the window is full, and that you start again when the window is empty. Part 1 needs to be working in order to pass the part 2 tests.



Style points are given by the instructor and TA after reading the code. Style is subjective, but will be graded on a scale from 1-5 where 1 is incomprehensible code and 5 means it is perfectly clear what the programmer intended. Style points may also be taken off for things like not exiting properly or other minor functional problems.

4. What to hand in

You must hand in a single file, either zip, tar, gzipped tar, bzipped tar or WinRAR (.zip, .tar, .tgz, .rar) that contains: (1) your library file, and (2) any other files for your library source code. (3) A README file.

error: Content is protected !!