This project has been made for Computer Networking Course at Ariel University.
It is a messaging app between serval clients, through a single server.
The clients can also download files from the server, using a UDP connection with reliabilty layers ontop of it.
Download server.py and frUDP.py to the same folder on your computer.
Create a new folder within it, called "files".
run server.py through CMD or through an IDE for python.
An IP will be written in the terminal, copy it and send it to your clients.
Make sure ports 55000-55015 are open and ready to be used.
Download client.py and frUDP.py to the same folder, run client.py through CMD or an IDE for python.
A small window will pop-up, insert a working IP of a server you want to connect to and wait for the connection to be established.
For a linux based client side you have to install the libraries manually, install tkinter.
First we will acknowlage that the simple messages are sent using TCP. Which means the state diagram is fixed, and as followed:
My implementation of CC is in frUDP is more simple, it is also based on unique acks for each segment of the file. When the server receives nack from the client, it lowers the amount of bytes sent at each packet. When the server does not receive and ack nor nack, it lowers the amount of bytes sent at each packet. This way, the download stays stable even though the connection is not. This way we over come packet losses and latency problems.
When the server is initialized, it always listens to a new client.
As stated in the diagrams section, the messages are sent using TCP so the header is fixed and as follows:
The implementation of headers in frUDP includes checksum, segment ID and data in bytes loaded into pickle (or json..)
FOR PAYLOAD (DATA IN BYTES)
32 bytes | rest of bytes |
---|---|
checksum | chuncks of 1000 bytes of data with unique segment ID for each chunk |
FOR MESSAGE DATA (DATA IN STRING)
32 bytes | 3 bytes | rest of bytes |
---|---|---|
checksum | segment ID | data in bytes of the string |
The managment of the two kinds of headers is easily observered in drUDP.py at lines 25-100. It is managed by the 4 functions: wrap() and unwrap() are for string data and wrap_payload() and unwrap_payload() are for data in bytes saved in a dictionary.
Inspired by TCP, I implemented three-way-handshake into frUDP.
It works the same way as TCP's does, the only difference is for optimization. Information such as 'filesize' is being transffered from the server to the client using the "SYN-ACK" message.
in frUDP.py there are two functions that are responsible for establshing frUDP connection: serverside_threewayhandshake() and clientside_threewayhandshake().
At first, the client sends the server a "SYN" message and waits for reply. Once the server receives the message it sends a "SYN-ACK" message, that is followed by 'filesize' which is the amount of bytes the server is intending to send to the client. The client receives the message and sends a final "ACK" message before the file tranfer initializes.
For the server there is a main thread that runs in a while true loop, and listens for new connections.
each connection receives 2 threads; one for listening and one for sending.
On the client it is simillar, once connection has been established 2 threads are being ran; one for lisetning and one for sending.
Once the client asks for a file, a new thread is initialized for the function "get_file" so the TCP connection is still running in the background.
On the server side, once a client asks for a file, two threads are being initialized, one for sending the file itself and one for listening for acks\nacks\ack-all.
.
On the client side in lines 75-85 I've implemented "fake packet loss simulation", where we can create packet loss and send nacks messages (or even not send nacks or acks for a specific packet).
Using this method, we could observe our changes in download speeds according to packet losses. (Congestion Control).
one of the most difficult things in this project was figuring out the values for changes in download speed at each nack or latency recognition
The following image shows the part of the code where you can create packet loss, send nacks or not send anything back to the server (as if the packet didn't arrive)
keep in mind that values[1] represents the amount of bytes (in thousands) that will be sent at a time.
if data[:4] == "NACK":
if values[1]>8:
values[1]-=3
...
...
elif data[:3] == "ACK":
list = eval(data[3:])
if values[1]<60:
values[1]+=1
The raw data for the following charts is in google sheets:
https://docs.google.com/spreadsheets/d/1wk7WyMW9k_cAbM6wEbKLBgx3a4vXbHEUQjmjdHLtLuA/edit?usp=sharing