Project 3
In
this assignment, you are going to replace the TCP file transfer in the previous
assignment with the UDP file transfer. Basically, you will implement a reliable
file transfer mechanism on top of the unreliable UDP. This is achieved by implementing
the Selective Repeat Protocol discussed in class. Because the protocol needs a
timeout value, you will implement the timeout estimation algorithm used by TCP.
In
this project, the server will be exactly the same as in the previous
assignment. The files size should be changed to 100,000 in common.h:
#define FILE_LENGTH 100000
Then,
the only change with regarding to the client is how it sends/receives the file,
which is explained in the following.
Let’s
say client A wants a file. Client A asks the server who has the file and the
server replies with client B.
1.
Setting
up a UDP connection.
a.
When client A receives the reply from
the server about client B, it tries to connect to client B with client B’s
listening port, and client B will accept this connection. Note that this connection is TCP.
b.
After the connection has been
successfully set up, client A should get a new UDP socket, call it udp_socket_a, and call the bind function with INADDR_ANY as the IP address and 0 as the port
number. The effect of this is that the system will find a port number to be
associated with udp_socket_a.
c.
Client A then uses getsockname() to find the port number associated with udp_socket_a, and prints it out. Then, client A will tell client
B the udp port number using the TCP connection with client B.
d.
When Client B receives the port number
from client A, it prints out this port number. Then, client
B will fork off a new process by calling the fork() function. The child process, denoted as B’, will be in charge of
sending the file to client A.
e.
B’ will get a new udp
socket, call it udp_socket_b, and calls the bind
function with INADDR_ANY as the IP
address and 0 as the port number. B’ will then find out the udp
port number associated with udp_socket_b¸ prints it
out, and send it to client A using the TCP connection with A. B’ will also use connect() function to connect udp_socket_b with client A’s IP address and the udp port number associated with udp_socket_a.
f.
When client A receives the message from B’,
client A prints out the port number. Client A will also use connect() function to connect udp_socket_a with B’s IP address and the udp port number associated with udp_socket_b.
Connecting two UDP sockets makes the coding a little simpler; you don’t have to
specify the remote address every time. Now B’ can send data to client A simply
by calling the send() function with upd_socket_b
as one of the parameters, and the format will be exactly the same as sending
data through TCP sockets. Similarly, B’ can receive data from A by calling the recv() function with upd_socket_b
as one of the parameters, and the format will be exactly the same as receiving
data through TCP sockets.
g.
Note that B’ will inherit all open file
descriptors from B, but it should not process any message sent to client B
because its only job is to send the file to client A. In fact it needs only one
socket, udp_socket_b. So B’ will close all other
opening file descriptors inherited from client B by calling the close() function.
2. The protocol. Now
Client A and B’ has set up a connection with UDP. B’ will get the file in the
buffer, and starts sending. Client A and B’ uses the Selective Repeat Protocol
for the file transfer. In this project, the sender and receiver window size are
both set to 10, and each slot holds 1000 bytes. We call each 1000 bytes of the
file a block. In this project, the sequence number can be 16 bits so you don’t
have to worry about the wrap around of sequence numbers. However, you can only
use a buffer of 10 blocks, so you need to worry about the wrap around of buffer
pointer. Also, you should implement the timeout of packets by the select
function.
The
protocol is:
Sender.
Assume the current window is m+1 to m+n.
while
(1) {
If
network layer has data and if current window not full yet: read data, send to
physical layer with the current sending frame ID, start timer, increment
sending ID.
If
got ACKw: if w is outside the window, don’t do
anything; if w is inside the window, consider all frames in the window with ID
no more than w acked and let m=w.
If timeout for frame w, resend frame w.
}
Receiver.
Assume the current window is m+1 to m+n.
while
(1) {
Wait (blocked here) and get frame from the physical layer. If it is
within the receiver window and hasn’t been received before, fill in the slot, forward the beginning of the receiver window
if necessary, and deliver to the network layer all frames between the beginning
of the old receiver window and the new receiver window – 1, inclusive. Send ACKm (m+1= the beginning of the current receiver window).
}
Note: assuming the sequence number is the frame ID.
Note: for simplicity, assume the receiver network
layer is always ready.
Print out:
·
Whenever the receiver receives a frame,
it prints out a line starting with the current unix time (in microsecond), including the sequence
number of the received frame, the current window, and the type of action it
will take, such as “12345678: Client 1 received frame seqnum
10, window [10-19], taking this frame, sending ACK 10.” It does not need to follow the exact format,
but should contain similar information.
·
Whenever the sender receives an ACK, it
prints out a line starting with the current unix
time, including the sequence number of the received ACK, the current window,
and the type of action it will take, such as “12345678: Client 2 received ACK seqnum 10, curr window [9-18],
moving window to [11-20].” It does not
need to follow the exact format, but should contain similar information.
·
Whenever the receiver sends an ACK, it
prints out a line starting with the current unix time, including the sequence number of the ACK
and the current window, such as “12345678: Client 2 sending ACK seqnum 8, window [9-18].”
It does not need to follow the exact format, but should contain similar
information.
·
Whenever the sender sends a frame, it
prints out a line starting with the current unix time, including the sequence number of the frame
and the current window, such as “12345678: Client 2 sending frame seqnum 15, window [9-18].”
It does not need to follow the exact format, but should contain similar
information.
·
The above are the necessary outputs to
check the progress of your code. You can also include other print out of your
own.
3.
Simulating
packet loss and delay. When Client A gets a UDP data
packet from B’, with probability p,
it drops it, where p is a parameter.
For the received UDP data packet that is not dropped, with probability p, client A does not send ACK at all. If
client A sends ACK, it does not do so immediately; instead, it delays for a
random amount of time to emulate the network delay. The length of the delayed
time is a random variable with value randomly taken from 50ms to 150 ms. Your client program should be augmented to be able to
take the parameter p when invoked in
the format: “-l 0.1”.
Print out:
·
Whenever the receiver drops a packet, it
prints out a line starting with the current unix time, including the sequence number of the frame
dropped, such as “12345678: Client 2 dropping frame seqnum
15.”
·
Whenever the receiver drops an ACK, it
prints out a line starting with the current unix
time, including the sequence number of the ACK dropped, such as “12345678:
Client 2 dropping ACK seqnum 15.”
4.
Estimating
RTT. B’ estimates the RTT (Round Trip Time) time by the
algorithm used by TCP.
·
RTT_new
= (1-g) * RTT_old
+ g * RTT_sample,
·
D_new
= (1-h) * D_old + h * |RTT_sample
- RTT_old|,
where
D denotes the estimation of the variance, and g=0.125, h=0.25. RTT_sample is obtained by measuring time elapsed between
sending a frame and receiving the ACK for this frame. It is suggested that when
the sender sends a frame, it puts the current time into this frame, and when
the receiver sends ACK, it should echo this field back in the ACK. Note that every
received frame will trigger an ACK; so if the sender receives an ACK, it knows
the RTT of the frame that triggered this ACK. The timeout TO is
set to be
·
TO = RTT + 4D
In our implementation, it is suggested that the initial
value of the RTT is set to be 100ms and initial value of D is set to be 0.
Print out:
·
Whenever the sender gets ACK for a
frame, it performs the above calculation, and prints out a line starting with
the current unix time,
including the new measured RTT_sample, RTT_new, D_new, and TO.
5.
Closing
the connection. After B’ received the ACK for the last
block, B’ sends 10 FIN frames and quits. Client A does not drop the FIN frame.
When client A gets a FIN frame, client A quits.
Print out:
·
When the sender sends FIN, it prints out
a line starting with the current unix
time and then indicating that it has quitted. When the receiver gets FIN, it
prints out a line starting with the current unix time and then indicating that it has quitted.