Reputation: 890
I'm trying to implement a UDP client program that receives a file from the server by sending multiple read requests and receiving small pieces of the file in return (1400 bytes, to prevent fragmentation). Each time I send a request, I set up a select() call with a timeout of 1 second. If I receive a response within that time, the client goes on to send the request for the next piece of file. Otherwise, the client resends the request for the same piece of file.
The problem with this sequential design is that the client waits for EACH request to be responded to before it sends the next one. If there is even a small ratio of packet losses, this would increase the time required for the sending of even a moderately large file to pretty unacceptable levels.
I would like to design the client to be able to send all of the read requests without waiting for responses, while simultaneously running a timer and retransmission loop that resends the individual requests that do not receive responses. However, I'm pretty new to coding in general, and can't seem to figure out how to do that. Do I need to open up several sockets at a time and run different loops on each? Or is there a more straightforward way of doing it?
My current code is (forgive the messiness):
def read_service_loop(self):
"""Loop governing the timing, checking, and retransmission or processing of read service. """
#Increment start_position each time packet sent, send a read request packet for each new position.
#Expect to receive a read_response packet for each time read request sent.
recv_data = None
print("Sending request to server to read and receive file...")
start_position = 0
while(self.eof == False):
print("Reading from byte " + str(start_position))
num_retransmits = 0
#Loop for retransmissions of the same start position
while(num_retransmits < 60):
num_retransmits = num_retransmits + 1
self.send_read_request(start_position)
input_socket = [self.client_socket]
inputready,outputready,exceptready = select.select(input_socket,[],[], 1)
if (inputready == []):
continue
else:
recv_data = self.client_socket.recv(self.buffer_)
bit_signature = recv_data[0:4]
response_type = recv_data[4:8]
recv_payload = recv_data[8:]
if bit_signature != "\x00\x00\x00\r":
self.recv_invalid_response(recv_data, "bit_signature")
continue
else:
if response_type == "\x00\x00\x00\x02":
#Packet is valid, proceed to recv_read_response to append this bit of file received into local_filename
self.file_append = open(self.local_filename, 'r+b')
self.recv_read_response(recv_payload)
break
else:
self.recv_invalid_response(recv_data, "response_type")
continue
start_position = start_position + self.NUM_BYTES_TO_READ
if (num_retransmits >= 60):
print ("Exceeded number of retransmissions allowed. Exiting program.")
sys.exit()
return
Upvotes: 0
Views: 1665
Reputation: 11
what you want to implement is called "sliding window", like TCP does. It will be complicated, because you need to take round-trip time into account. It is still evolving, see how TCP implementations of different operating systems have different performances. Perhaps you can find some library that already implements it.
Any reason not to use TCP?
Upvotes: 1