Cleveland State University

Department of Electrical Engineering and Computer Science

CIS454/554 Data Communication Networks

Term Project#1:

Implementing a Reliable Data Transfer Protocol


In this project, you will be implementing the rdt3.0 protocol covered in lecture 7. In this project description, we refer this protocol as PAR (Positive Acknowledgement with Retransmission) protocol.


The execution of network protocols is typically event-driven. Such events include the arrival of a message from the lower or higher level, and the expiration of a timer. The event is often called an interrupt.


Consider a layer n and its adjacent layers n+1 and n-1, as shown in the figure above. When layer n+1 has a message to send, it invokes the send interface provided by the layer n and passes the message to layer n. Layer n maintains a send buffer to store message to be sent (and to be retransmitted). If the buffer is already full when layer n+1 tries to send a message, an error will be returned. The send call will trigger an event so that the thread that is executing the layer n protocol can fetch the message in the send buffer and passes it to the lower layer (n-1) afternoon adding a layer n header.


Similarly, when a message arrives at layer n-1, an event is generated and the layer n protocol thread is woken up to handle the message. In general, the message is initially stored in a receive buffer of layer n before it is delivered to layer n+1, for a number of reasons (e.g., to ensure source ordering in TCP). In our PAR protocol, this buffer is not used because the message is delivered right away.


Since layer n-1 might be lossy, layer n must implements a retransmission mechanism to retransmit the messages to be sent, if the acknowledgement does not arrive in time. To do this, the protocol starts a timer each time it transmits (or retransmits) a message. If the timer expires, an event is generated and the protocol thread is woken up to perform the retransmission operation.


Event-driven programming is not trivial. Therefore, you are provided with Java skeleton code and the binary (Java byte code) files for a reference implementation for this project. In the reference implementation, the main thread executes the PAR protocol, and a separate thread is used to pick up messages arrived from UDP in the simulated network layer. The timer is implemented using the facility provided by Java (java.util.Timer and java.util.TimerTask). You are strongly encouraged to build your project based on the skeleton Java code. However, you are free to choose a different programming language if you wish, in which case, you will have to implement the simulation environment as well as the PAR protocol from scratch.


For completeness, the PAR finite state machine specification for the sender and receiver (partial) is shown below:



Partial finite state machine for the receiver (it is the same as that for rdt2.2).

Finite state machine specification for the sender.


The reference implementation consists of the following files:



How to run the reference implementation binaries:



To keep the difficulty of the project in the reasonable level, most of the files above will be provided with full implementation. Your tasks include:


  1. Thoroughly read and understand the code provided (This task does not apply if you choose to implement this project in a different language)
  2. Complete the main protocol loop in the run() method in RarReceiver and ParSender classes.
  3. Modify the send() method defined in the LossyChannel class so that you can control the loss rate dynamically. The reference implementation has a hard coded loss rate of 30%, i.e., 3 packets will be lost for every 10 packets sent. There are a number of ways you can use to convey the loss rate information dynamically (i.e., at runtime) to the program, e.g., through command line, environment variables and Java Properties. Please consult with the Java Tutorial for detail:
  4. Modify the getMessageToSend() method in ParSender class so that it can fetch packets to send from a file (ASCII file would be fine).
  5. Modify the deliverPacket() method in ParReceiver class so that it extracts the packet from  the frame received and write the payload into a file.
  6. The above two tasks enable the measurement of the performance of the PAR protocol. You need to instrument the ParSender class to measure the total time required to transmit a big file. If you choose to use an ASCII file, it should include at least 1,000 lines. You need to perform the latency measurement under the following configurations: 0 loss, 10% loss, 20%, and 30%. You can take the measurement on the same machine, or on two computers. The measurement result can be reported in a table or in a figure.




Extra credit (3% of the course):

The reference implementation has only a simple verification test on the correctness of the frames received. It includes a preamble with each frame sent and check the validity of the preamble. This check does not work if the transmission error occurs after the preamble part in a frame. To improve the current implementation, you need to compute a checksum for each frame and include the checksum as a trailer in each frame sent, and verify the checksum of each frame received.


Because UDP ensures no corruption for packets delivered, you need to instrument the LossyChannel class’s send() method to inject corruption into packets to be sent. Again, the corruption incidence should happen randomly with controllable probabilities, just like the segment loss rate.


Appendix: How to run the reference implementation binaries in Eclipse: