diff --git a/client.py b/client.py index 4a074ba..6edc5ff 100644 --- a/client.py +++ b/client.py @@ -1,5 +1,8 @@ -timeout = 1 +timeout = 0.5 +local_server = False serverAddressPort = ("213.47.107.152", 1337) +if local_server: + serverAddressPort[0] = "127.0.0.1" possible_value = input("Enter a value: ") filename = possible_value if (filename := possible_value) else "data.bin" @@ -8,9 +11,18 @@ import socket, struct, select, time, math import hashlib -#import brotli #pip install brotlipy +#convert bps to Kbps, Mbps, Gbps if they are >= 1000 +def convert_to_highest_speed(bps): + if bps < 1000: + return f'{round(bps,2)}bps' + elif bps < 1000**2: + return f'{round(bps/1000,2)}Kbps' + elif bps < 1000**3: + return f'{round(bps/1000**2,2)}Mbps' + elif bps < 1000**4: + return f'{round(bps/1000**3,2)}Gbps' -max_frame_payload=508 +max_frame_payload=1016 #508 is the minimum size for routers to "understand" udp packets, but we can possibly send more data header = "!L16s" header_size = struct.calcsize(header) max_payload = max_frame_payload - header_size @@ -58,8 +70,8 @@ while packets > 0 or serverhash == None: if ready[0]: datareceived = UDPClientSocket.recvfrom(max_frame_payload)[0] - if len(datareceived) == 64: - serverhash = struct.unpack("64s", datareceived)[0] + if len(datareceived) == 65: + serverhash = struct.unpack("64sx", datareceived)[0] continue if len(datareceived) != max_frame_payload: print("\nerror bad packet: wrong size",len(datareceived)) @@ -71,6 +83,7 @@ while packets > 0 or serverhash == None: print("\nerror bad packet: received multiple times",seq) continue + #check if packet is last packet and cut data to last packet size if seq == total_packets-1: #print("len before cut",len(data)) @@ -84,35 +97,57 @@ while packets > 0 or serverhash == None: print(data.hex()) continue + #print(seq) + #print(data) + + #data = deflate.gzip_decompress(data) + data_packets[seq] = data packets -= 1 else: - #collect packets that were not received and send them in one message + #collect packets that were not received and send them in n messages + #where n is the minimum amount of messages needed to request all packets + msg = message + lost_packets = [] for i in range(len(data_packets)): if data_packets[i] == None: - #print("requesting packet", i) - UDPClientSocket.sendto(str.encode(f"{message}/{i}"), serverAddressPort) + lost_packets.append(i) + + #split lost_packets into groups of size 508-msg.length bytes + current_packets = [] + for i in range(len(lost_packets)): + if len(str(lost_packets[i])) + len(msg) + 1 > max_frame_payload: + current_packets.append(msg) + msg = message + msg += f"/{lost_packets[i]}" + + if len(lost_packets) > 0: + timeout *= 2 #increase timeout to relieve internet connection and server + current_packets.append(msg) + for msg in current_packets: + UDPClientSocket.sendto(str.encode(msg), serverAddressPort) + #print(f'requested lost packets {msg}') + if serverhash == None: UDPClientSocket.sendto(str.encode(f"{message}:"), serverAddressPort) - print(f'{total_packets - packets}/{total_packets} | {math.floor((total_packets - packets)/(time.time()-time_started if (time.time()-time_started)!=0 else 1)*max_payload)}Bps'+'\t'*10, end='\r') + download_speed = (total_packets - packets)/(time.time()-time_started if (time.time()-time_started)!=0 else 1)*max_payload + print(f'{total_packets - packets}/{total_packets} | {convert_to_highest_speed(download_speed)}'+'\t'*5, end='\r') -print("finished transfer", end='\r') +print("finished transfer" + "\t"*5, end='\r') for packet in data_packets: sha512.update(packet) sha512 = sha512.hexdigest() -print('sha512: %s' % sha512) - -print('server sha512: %s' % serverhash.hex()) - if sha512 != serverhash.hex(): - print('hash mismatch') + print('sha512: %s' % sha512) + print('server sha512: %s' % serverhash.hex()) + print(f'hash mismatch, writing corrupt file to disk: {filename}.corrupt') with open("received/"+filename+".corrupt", 'wb') as f: f.write(total_data) exit()