This programming assignment should be templated and then cloned. You should clone your templated repo and not this repo. See section at end of this document on how to hand in this assignment.
This exercise aims to create a simple UDP file transfer system, where a client will send a file to a server, and the server will receive the file and save it to disk. There are no limits on the size of the file.
In this mini-project, you will implement a simple protocol for file transfer over UDP. Because the socket is UDP, the application layer is responsible for ensuring that the file is transferred without error. While this algorithm addresses some of the reliability transfer issues, many problems related to reliable transfer still need to be addressed.
Note: This mini-project is intended to provide practice in socket programming. File transfer should be done over a TCP socket. This will be the subject of the next mini-project.
The algorithms described below implement the following simple protocol.
Figure 1: Simple file transfer protocol.The server should:
- Create a socket using the
socket
function and bind it to the (ip, port) pair. (Implemented) - Receive a message from the client using the
recvfrom
function. - Decompose the message into an 8-byte integer representing file size. The rest of the bytes should be decoded into a string representing the file name. Use
get_file_info()
. - send
b'go ahead'
message to the client. - To upload the file, Create an SHA256 object to compute the sha256 hash of the received file
- Using the filename provided, open the file for writing using the with python statement. NOTE: since you will be transferring a file over localhost to the same directory, it is important that you modify the filename, say by adding a .temp extension, to avoid overwriting the original file. (Implemented)
- Inside the with statement,
- Receive a chunk of data.
- Write the data to the file.
- Update the sha256 hash.
- Send the message `b'received'` back to the client. The client should not send the next chunk until a `b'received'` message is received by client.
- Continue to perform steps 7a-c until all bytes have been received.
- The server should then wait to receive the file hash calculated by the client and compare it to the hash calculated by the server.
- If the hashes are the same, the server should send a 'success' message to the client; otherwise, it should remove the file and send a 'failed' message to the client.
- Repeat steps 2 - 9.
The client should:
- Obtain the name of the file to transfer from the command line using sys.argv. (Implemented)
- Obtain the size of the file in bytes by using the os.path module.(use
get_file_size()
) - Convert the file size to an 8-byte string using big endian.
- Create a SHA256 object using the hashlib module, to calculate the sha256 hash of the file.
- Create a socket using the
socket
function. (Implemented) - Send the 8-byte file size concatenated with the encoded filename to the server.
- Wait for the server to send
b'go ahead'
message. If any other message is sent,raise Exception('Bad server response - was not go ahead!')
- Open the file for reading in binary mode using the with python statement.
- Read a chunk of data from the file.
- If the length of the chunk > 0, then
- Update the hash.
- Send the chunk to the server.
- Receive a 'received' acknowledgment from the server. If a message other than 'received' is received, then `raise Exception('Bad server response - was not received')`.
- If the length of the chunk read is 0, then go to step 9. No more chunks to read and send.
- Repeat steps 8a - 8d
- Send the server the calculated hash digest (NOT hexdigest) as a byte string.
- Receive a
b'success'
orb'failed'
message. - If a
b'failed'
message is received,raise Exception('Transfer failed!')
elseprint('Transfer completed!')
- Close the client socket. (Implemented)
You can test your implementation by first implementing the client and running it against a correctly implemented server at 20.33.20.21:12000. Once the client works you can test your server using your working client.
NOTE: as mentioned in section 1 above, it is important that you modify the filename, say by adding a .temp extension, to avoid overwriting the original file. This has already been done on the server's with
statement. Such a filename change is only necessary when running both server and client on the same machine and using the same working directory. You do not have to modify the filename if you set the run configuration of the server to use a different working directory from that of the client.
Your instructor will provide further information as to how to test both your client and server on a remote instance.
You are required to submit this work using the CodeGrade link on Blackboard.
- Make sure to handle errors in your code.
- Pay attention to the TODO tasks and how they are mapped to the algorithm steps above. This will help guide you in implementing the code.
- Read the Python documentations for the hashlib, sys, os, and os.path modules along with associated examples. Avoid Googling the answer as this will get you into the habit of reading documentaton.
Good luck and happy coding!