import argparse import math import os import socket MSS = 20476 # MSS = Server buffer size (20480) - data header size (4) def await_ack(packet): s.settimeout(1) while True: try: data, addr = s.recvfrom(1024) print(f"Server: {data.decode()}") received_ack_seqno = int(data[2:3].decode()) expected_ack_seqno = (int(packet[2:3].decode()) + 1) % 2 if received_ack_seqno != expected_ack_seqno: continue return True except KeyboardInterrupt: print("Client: Exiting...") exit() except socket.timeout: # Expected ACK was not received within one second print(f"Client: Retransmitting...") s.sendto(packet, (server_ip, server_port)) if __name__ == "__main__": parser = argparse.ArgumentParser() parser.add_argument("server_addr", type=str) parser.add_argument("file_path", type=str) args = parser.parse_args() server_ip, server_port = args.server_addr.split(":") server_port = int(server_port) file_name = args.file_path.split(os.path.sep)[-1] file_size = os.path.getsize(args.file_path) with socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM) as s: s.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, 30000) # Check file existence if not os.path.exists(args.file_path): print(f"Client: no such file: {args.file_path}") exit() # Send start packet to server packet = f"s|0|{file_name}|{file_size}".encode() print(f"Client: {packet.decode()}") s.sendto(packet, (server_ip, server_port)) # Wait for ACK for the given packet await_ack(packet) # Upload file to server seqno = 1 with open(args.file_path, "rb") as f: for i in range(math.ceil(file_size / MSS)): print(f"Client: d|{seqno}|chunk{i + 1}") packet = bytes(f"d|{seqno}|", "utf-8") + f.read(MSS) s.sendto(packet, (server_ip, server_port)) await_ack(packet) seqno = (seqno + 1) % 2