【CSC2035可靠文件传输】CSC2035 Assignment 2 Coursework Specification
A Reliable File Transfer protocol that works on top of UDP
Maximum mark: 100. This assignment is worth 25% of the overall module mark.
Due date: 15:00 Wednesday 19 May 2021 in NESS
Aim
This coursework gives you the opportunity to develop your skills in network socket programming using
the C programming language. The aim of this coursework is to build a Reliable File Transfer (RFT)
protocol that works on top of UDP and guarantees reliable delivery of a file between a client and a
server.
Coursework Description (please read carefully)
This coursework has three parts:
? Part 1: Protocol RFT using the PAR protocol in the absence of errors (60 marks)
? Part 2: Protocol RFT using the PAR protocol with re-transmission (30 marks)
? Part 3: Report (10 marks)
You can use the C programming environment you used for assignment 1 to complete this assignment.
To make sure you understand how to do this, you must do the Canvas Assignment 2 UDP socket
programming preliminary exercise
For this assignment, you are given some initial code in the zip archive csc2035-assignment2-init.zip. It
contains the following files:
? Makefile – the project make/build file
? in_*.txt – text input files of various sizes that you can use to test your solution. Your solution
should work correctly for all of these input files. The sizes of the different files have been
chosen deliberately to test various boundary conditions.
? rft_client.c – The client application code
? rft_client_util.c – The client utility library that contains the functions you have to implement
(this is the file you edit).
? rft_client_util.h – The header file for the client utility library that includes the specification of
the functions you have to implement
? rft_server.c – The server application code
? rft_util.c – The implementation of utility functions used by client and server
? rft_util.h – The specification of utility functions and data structures used by client and server
The above files are the starting point for your solution. You implement the following four functions
in rft_client_util.c:
? create_udp_socket (for Part 1)
? send_metadata (for Part 1)
? send_file_normal (for Part 1)
? send_file_with_timeout (for Part 2)
2
You must implement them as specified in this document and according to their specifications in
rft_client_util.h. Do NOT change any of the other files provided or any other parts of rft_client_util.c.
You must NOT change function signatures. YOU WILL BE MARKED AT 0 IF YOU DO.
Part 1: Protocol RFT using the PAR protocol in the absence of errors (60 marks).
Description: The RFT protocol uses the UDP protocol to send a file from a client to a server. The
operation starts by sending the file metadata (size and output name) to the server. The actual file is
then sent.
UDP is an unreliable connectionless transport layer protocol that has no means of guaranteeing
reliable delivery of a file. However, networks can lose, corrupt or delay segments. To work around
this, our RFT protocol will implement the PAR protocol to guarantee a reliable transport service (see
‘Data Link Layer’ of lecture notes for more details about the PAR protocol and think of “segments”
instead of “frames”). This means that:
? Data segments are sent from a client to a server and ACK segments are sent from server to a
client. The segment type is one of DATA_SEG or ACK_SEG as defined in rft_util.h.
? The client does not send the next data segment unless it receives an ACK segment for the
previous data segment (the sequence number of the ACK segment should be the same as that
of the data segment).
? Some additional information is added to the header to guarantee a proper implementation of
this protocol: a sequence number which could be used to detect duplication, a checksum to
detect any corruption in the data, and a flag to indicate that the last segment is being sent.
These are defined as part of the segment struct in rft_util.h.
? The data segment payload is the data that is read by the client from the input file and the
segment also provides the number of bytes of payload that are being sent.
? You must ensure that the payload of a segment is filled with 0s after any valid characters, this
allows payload to be treated as a string by the server. Hint: the simplest way to achieve this is
for the client to initialise the payload buffer to 0 before each read from the input file and to
read less than the full buffer on each read.
In the first version of the protocol (for Part 1) we assume an absence of errors. This means that you
do not need to consider issues that affect the segments while travelling acrossthe network (e.g. delay,
losing data segments, losing ACK segments or corrupted segments).
To simplify the solution, you have been given the server code (rft_server.c). DO NOT change the server
code.
? The main() function in rft_server.c checks that the number of input arguments is correct (i.e.
the port number), then it creates a UDP socket and binds to it because the client needs a fixed
port number to send the file to. The server then receives the metadata sent by the client:
output file name and the total file size. This is implemented in rft_util.h as the metadata struct.
Once this is received, the server is ready to receive the actual file.
? The receive_file_normal() function receives the file in segments, each of which has a payload
of up to PAYLOAD_SIZE characters including at least one terminating 0 (see the segmentstruct
in rft_util.h). For each received segment, the server calculates and validates the checksum. If
the checksum is correct, the server will write the content to the output file and it will send an
ACK segment to the client with the same sequence number as the one in the received data
segment. This is to inform the client that the data segment has been received properly. If the
checksum is not correct, the server will not write anything to the output file and will not send
3
an ACK. The server terminates once it receives a segment with the last flag set to true (or 1).
This signals that the received segment is the last one in the sequence of one or more segments
You have also been given client application code in rft_client.c. The main() function of rft_client.c
will first check that the user enters the right number of arguments (inputfile, outputfile, server
address, port number and transfer mode – see the comments in rft_client.c). It then opens the input
file for reading and then uses the following functions you implement in rft_client_util.c to do the file
transfer:
? create_udp_socket
? send_metadata
? send_file_normal or send_file_with_timeout depending on transfer mode.
In the version of rft_client_util.c that you are given, all 4 of the above functions cause the client
application to exit with an error message.
To start, implement the following two functions:
int create_udp_socket(struct sockaddr_in server, char server_addr, int port)
? create_udp_socket creates a socket for the client to communicate with the server and fills in
the server address struct. Hint: look at the code for the preliminary exercise and the server
code. See also rft_client_util.h
bool send_metadata(int sockfd, struct sockaddr_in server, off_t file_size, char output_file)
? This function sends the file meta data to the server (i.e. file size and output name). Hint: look
at the use of sendto in server code and the man page for sendto. Make sure that you deal with
send errors and in the event of failure, close any open resources provided to the function. See
also rft_client_util.h
After you implement the above two functions, you can run the client and server code to check that
the socket was created and the server is able to receive the metadata. Information on how to do this
and expected output is provided in Appendix 1.
Use make to compile the project. Note, until you complete Part 2, make will produce a warning that
is_corrupted is an unused function.
If you get the expected output and think that you have implemented create_udp_socket and
send_metadata correctly, now implement:
size_t send_file_normal(int sockfd, struct sockaddr_in* server, int infd, size_t bytes_to_read)
? This function executes the PAR protocol with the server to do the actual file transfer.
? The file is sent in a sequence of chunks of PAYLOAD_SIZE – 1. These chunks of data are sent
as the payload field of a data segment. You need to fill in the other fields of each segment as
appropriate (including the checksum field calculated using the checksum() function provided
– with the is_corrupted parameter false). The payload size may be less for the final segment
because the file size may not be a multiple of the size of each chunk of data stored in the
payload field. Note: the server expects to be able to treat the payload data as a string.
4
Therefore, the bytes read and sent for each segment is always at least 1 less than
PAYLOAD_SIZE.
? The function proceeds by starting from the beginning of the file, reading a chunk of data into
the payload buffer, then sending the data segment to the server with all fields of the segment
completed, then waiting for the server to ACK the data segment message and then, if
necessary, repeating the read-send-ACK process until the whole file has been read and sent.
? The last segment is signalled to the server by setting the last flag of the segment.
? The client exits when the last segment has been sent (and ACKed) and there is no more data
to read from the input file.
? You have to deal with errors that may occur and exit with an error message when appropriate
(after closing open resources that were provided to the function).
? Hints:
? look at the use of sendto() and recvfrom() in the server code
? You can read from the input file using any I/O library function you wish. Possibilities
are one of read, fread or fgetc. You should investigate each of these and decide which
is most appropriate. If you use fread or fgetc you will have to associate the file
descriptor provided as a parameter to the function with a file stream (see fdopen).
? See also the documentation of the function in rft_client_util.h
Test your program by running the server code first and then the client code. For the client, choose
command line option "nm" for normal file transfer.
After the transfer is complete, if your code is correct then the input file read by the client and the
output file written by the server should be exactly the same. You can use the diff command to verify
this. The marker will check this in addition to checking your code.
You can use the different in_*.txt files to test your program with different file sizes.
In addition to functioning implementations of the create_udp_socket, send_metadata and
send_file_normal functions you are expected to output useful information messages for the user
from create_udp_socket and send_file_normal functions.
Appendix 2 provides example output for working versions of all three functions and shows the sort of
information messages that are expected.
Use the utility functions: print_cmsg, print_cerr, print_sep and exit_cerr to produce output.
Hint: see server code for equivalent output and for exiting with an error and the use, where necessary,
of a buffer to construct information output.
Part 2: Protocol RFT using the PAR protocol with re-transmission (30 marks).
In this part you enhance the RFT protocol to cope with data segment loss and corruption. This can be
done by using a timer that expires if no ACK has been received and then resending the data segment
(with recomputed checksum). To do this implement:
size_t send_file_with_timeout(int sockfd, struct sockaddr_in* server, int infd, size_t
bytes_to_read, float loss_prob)
? You can copy some of the code you have used for send_file_normal and add the code
necessary to address the following
5
? Simulating packet corruption: Sending a file between a client and server on the same
machine is reliable. To be able to simulate the errors that may happen in real-world
networks, you need to artificially create some corrupted segments. To do this, the
is_corrupted function is given to you. This function, when given a probability between
0.0 and 1.0, returns either true or false with that probability. The loss_prob parameter
to the send_file_with_timeout function is the probability parameter to use for the
is_corrupted function. The result of the is_corrupted function can be passed as the
second parameter to the checksum function and thereby simulate corruption of a
segment (when is_corrupted returns false). You should output an information
message that indicates network corruption of a segment "has occurred".
? Timeout and re-transmission: The client waitsfor a specific period of time for an ACK.
When the period times out (i.e. an ACK has not been received), the client resends the
data segment with a recomputed checksum. Hint: to implement a timeout,
investigate the setsockopt and select library functions. It is up to you to decide on the
length of a timeout.
Make sure that you assist the user by printing some meaningful messages. Your output should
explicitly show that the client has timed out and that the same segment with the same content is retransmitted.
You also need to show the total number of sent segments including any re-transmitted
segments.
Also see the documentation of the function in rft_client_util.h.
To test your code, follow the same process as for Part 1 except use the wt command line option for
the client program with a loss probability between 0.0 and 1.0.
You should run a number of transfers with different probabilities. For example, try loss probabilities
of 0.0 (no corruption), 1.0 (all segments corrupted) and 0.3 (approx. 1/3 of segments corrupted).
Part 3: Report (10 marks):
Provide a report that covers the following:
? A list of the functions you have completed.
? Screenshots of client and server terminal output for each of the following scenarios and a brief
description of the behaviour:
? Normal PAR/transfer protocol (Part 1)
? PAR protocol with re-transmission after timeout (Part 2).
Assignment Submission
Submit the following two files to NESS in a zip archive:
? Your rft_client_util.c file
? Your report (Part 3) as a Word or PDF document.
Do NOT submit any other files. Anything other than the two files listed above will be ignored
6
Additional notes
? rft_server.c does not check the sequence number of the incoming data segment. In these
protocols the sequence number is for information only.
? Do NOT change any function signatures. You can add helper functions to rfc_client_util.c if
you think they are necessary. Any such functions must be used by the 4 functions you are
asked to implement in Parts 1 and 2.
? Do not over complicate your code.
? All the submitted code will be checked for plagiarism.
7
Appendix 1: testing metadata send (first two functions in Part 1) and expected output
When you have implemented create_udp_socket and send_metadata, you can test they work as
follows.
First, compile the project by typing:
make
Note, until you complete Part 2, make will produce a warning that is_corrupted is an unused function.
Assuming compilation succeeds, you can now run the server and client. As in the preliminary exercise
on Canvas, you run the server first in one terminal and the client in a second terminal.
To run the server, type:
./rft_server 20XXX
where 203XX is the port number you select (see the information in the preliminary exercise on Canvas
推荐阅读
- CIS 657操作系统
- COM1005 Rambler问题
- 谈谈COMP3310
- CPT206
- PROG2005 移动
- 后端|git命令【超实用】【已应用,已实践】
- CS‐521 讲解
- 后端|visual studio如何配置opencv
- C++|C++模板初阶——函数模板与类模板