$29.99
Purpose of the Assignment
The general purpose of this assignment is to continue to explore network programming and principles of reliable data transfer, leveraging the chat client and server constructed for Assignment #2 and used again in Assignment #3. This assignment is designed to give you further experience in:
writing networked applications the socket API in Python creating UDP applications techniques for reliable data transfer
Late Penalty
Individual Effort
Your assignment is expected to be an individual effort. Feel free to discuss ideas with others in the class; however, your assignment submission must be your own work. If it is determined that you are guilty of cheating on the assignment, you could receive a grade of zero with a notice of this offence submitted to the Dean of your home faculty for inclusion in your academic record.
What to Hand in
Assignment Task
You are required to take your TCP-based chat client and server from Assignment #3 and replace its use of TCP with UDP. In the process, you are to implement a reliable data transfer protocol on top of UDP to ensure that your application can tolerate lost and corrupted packets. As a result, you will need to provide additional code for error detection, retransmission, and timeouts.
RDT Sender:
RDT Receiver:
Some Particulars
Here are some specific requirements and other important notes:Â
The same chat functionality, including following and file attachments, from Assignment #3 is required for this assignment. Please refer back to the specification for Assignment #3 for more detail. Â
To assist in the process, you will want to create new send and receive functions and encapsulate all RDT functionality into those functions. That will make things easier to drop into an existing code base without disturbing existing application functionality already in place. That might not cover everything needed to support reliability, but it should help with most things. (For example, you could create a new send() function that packs your data, checksums it, sends it along, and then doesn't return until the data has been acknowledged successfully.)
To help manage timeouts, likely the most straightforward way is to leverage the use of Python selectors, as we've already been using those in earlier assignments. Interestingly, the select() function supports an optional timeout that you can use to help detect missing acknowledgements. (A fixed timeout of 1 or 2 seconds is likely sufficient, but feel free to pick something else that is appropriate.) There are of course other ways of doing this, but this is at least one that you are already familiar with. You will have to be careful with choosing when to block and when not to block, but you are already familiar with this as well.
To test your program, you need a way to insert errors into your packets, and to periodically drop packets. If only someone could create some kind of a tool or simulator for UDP to do this sort of thing? Oh wait, I already did. And you used it as part of Assignment #1. Yes, this means it's must time again! You can use its various options to inject errors (avoid setting the rate higher than 0.0001 for a bit error rate of 0.0001%) and to lose packets ( I would not set it much higher than 10% or 20%). If you crank those options too high, it will be hard to get data through and you're making life unnecessarily difficult. For instructions on how to use must and for code, please refer to Assignment #1. (Also, remember that a slightly updated version was posted under our Announcements.)
To make your life easier, take a very incremental approach to doing things. Do not use must at first, as it might complicate things. Start by just creating your packet structures, sending them, receiving them, and unpacking them on the other side, without worrying about any reliability protocol. (There is no point in complicating things if the packet structures cannot be moved around on their own!) After this, add the error detection functionality and test it by injecting errors with must. Next, add retransmission functionality, and test that it works using must. After this, add the loss handling capabilities as well and again test it with must. In essence, taking a step-by-step approach similar to how we refined the RDT protocol in class is a good idea. If you do too much at once, and then run into troubles, it will be much harder to tell where you went wrong!
You are to provide all of the Python code for this assignment yourself, except for the sample code attached to this assignment and code used from
the Assignment #3 implementation provided to you.  (You can also reuse your own Assignment #3 code as well.)  You are not allowed to use Python functions to execute other programs for you, nor are you allowed to use any libraries that haven't been explicitly allowed.  (If there is a particular library you would like to use/import, you must check first.)  All server code files must begin with server and all client files must begin with client*.  All of these files must be submitted with your assignment. Â