×
Samples Blogs Make Payment About Us Reviews 4.9/5 Order Now

Create a Program to Implement Networking in Python Assignment Solution

June 25, 2024
Dr. Nicole
Dr. Nicole
🇬🇧 United Kingdom
Python
Dr. Nicole, an accomplished professional with 6 years of experience, obtained her Ph.D. from Princeton University. Having completed over 400 Python assignments, she brings a wealth of expertise and insight to the table. With a focus on clarity and precision, Dr. Nicole is committed to providing comprehensive support to students seeking assistance with their Python projects.
Key Topics
  • Instructions
    • Objective
  • Requirements and Specifications
Tip of the day
Familiarize yourself with OCaml's pattern matching; it simplifies handling recursive data structures like lists and trees, making your code concise and easier to debug.
News
In 2024, Girls Who Code introduced a Data Science + AI track in their free summer programs for high school students, fostering skills in cybersecurity and creative coding​

Instructions

Objective

Let's tackle the task of implementing networking in Python. Networking is a crucial aspect of modern software development, allowing programs to communicate and exchange data over various networks. To complete your Python assignment, you might need to create client-server applications, work with sockets, or use higher-level libraries like Requests for HTTP communication. By understanding the fundamentals of networking and utilizing Python's powerful libraries, you can successfully accomplish your assignment's objectives.

Requirements and Specifications

program-to-implement-networking-in-python (1)
program-to-implement-networking-in-python 1

Source Code

SENDER

import threading import time import random import socket import select import argparse from functools import reduce # Settings # Retransmission timeout RTO = 0.500 # Number of application bytes in one packet CHUNK_SIZE = 8 # Initial sequence number for sender transmissions INIT_SEQNO = 5 # dummy ACK number for sender's packets __ACK_UNUSED = 2345367 # Message class: we use this class to structure our protocol # message. The fields in our protocol are: # seq no: the starting sequence number of application bytes # on this packet # ack no: the cumulative ACK number of application bytes # being acknowledged in this ACK # len: the number of application bytes being transmitted on # this packet # msg: the actual application payload on this packet # The methods `serialize` and `deserialize` allow the # conversion of a protocol object to bytes transmissible # through a sendto() system call and the bytes from a # recvfrom() system call into a protocol structure. class Msg: def __init__(self, seq, ack, msg): self.seq = int(seq) self.ack = int(ack) self.msg = str(msg) self.len = len(self.msg) def serialize(self): ser_repr = (str(self.seq) + ' | ' + str(self.ack) + ' | ' + str(self.len) + ' | ' + self.msg) return ser_repr.encode('utf-8') def __str__(self): repr = "Seq: " + str(self.seq) + ' ' repr += "ACK: " + str(self.ack) + ' ' repr += "Len: " + str(self.len) + ' ' repr += "Msg: " + self.msg.strip() return repr @staticmethod def deserialize(ser_bytes_msg): ser_msg = ser_bytes_msg.decode('utf-8') parts = ser_msg.split('|') if len(parts) >= 4: return Msg(int(parts[0]), int(parts[1]), '|'.join(parts[3:])[1:]) else: print("Error in deserializing into Msg object.") exit(-1) ### Helper methods. #### Initialize a UDP socket def init_socket(receiver_binding): try: cs = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) print("[S]: Sender socket created") except socket.error as err: print('socket open error: {} \n'.format(err)) exit() return cs #### Slurp a file into a single string. #### Warning: do not use on very large files def get_filedata(filename): print ("[S] Transmitting file {}".format(filename)) f = open(filename, 'r') filedata = f.read() f.close() return filedata #### Chunk a large string into fixed size chunks. #### The first chunk is a string with the number of #### following chunks. #### `seq_to_msgindex` tracks the index of the packet #### that will contain a given sequence number as its #### starting sequence number. def chunk_data(filedata): global CHUNK_SIZE global INIT_SEQNO messages = [filedata[i:i + CHUNK_SIZE] for i in range(0, len(filedata), CHUNK_SIZE)] messages = [str(len(filedata))] + messages content_len = reduce(lambda x, y: x + len(y), messages, 0) seq_to_msgindex = {} accumulated = INIT_SEQNO for i in range(0, len(messages)): seq_to_msgindex[accumulated] = i accumulated += len(messages[i]) return messages, content_len, seq_to_msgindex #### Parse command line arguments def parse_args(): parser = argparse.ArgumentParser() parser.add_argument('--port', type = int, help = "receiver port to connect to (default 50007)", default = 50007) parser.add_argument('--infile', type = str, help = "name of input file (default test-input.txt)", default = "test-input.txt") parser.add_argument('--winsize', type = int, help = "Window size to use in pipelined reliability", default = 20) args = parser.parse_args() return vars(args) ############################################ # Main reliable sending loop def send_reliable(cs, filedata, receiver_binding, win_size): global RTO global INIT_SEQNO global __ACK_UNUSED messages, content_len, seq_to_msgindex = chunk_data(filedata) win_left_edge = INIT_SEQNO win_right_edge = min(win_left_edge + win_size, INIT_SEQNO + content_len) # Method to transmit all data between window left and # right edges. Typically used for just fresh # transmissions (retransmissions use transmit_one()). def transmit_entire_window_from(left_edge): latest_tx = left_edge while latest_tx < win_right_edge: assert (latest_tx in seq_to_msgindex) index = seq_to_msgindex[latest_tx] msg = messages[index] if (latest_tx + len(msg) <= win_right_edge): m = Msg(latest_tx, __ACK_UNUSED, msg) cs.sendto( m.serialize(), receiver_binding) print ("Transmitted {}".format(str(m))) latest_tx += len(msg) else: break # return last seq no that was actually transmitted return latest_tx # Transmit one packet from the left edge of the # window. Used for retransmissions in pipelined # reliability, and also for fresh transmissions in # stop-and-wait reliability. def transmit_one(): assert (win_left_edge in seq_to_msgindex) index = seq_to_msgindex[win_left_edge] msg = messages[index] m = Msg(win_left_edge, __ACK_UNUSED, msg) cs.sendto(m.serialize(), receiver_binding) print ("Transmitted {}".format(str(m))) return win_left_edge + len(msg) # TODO: This is where you will make your changes. You # will not need to change any other parts of this file. while win_left_edge < INIT_SEQNO + content_len: win_left_edge = transmit_one() if __name__ == "__main__": args = parse_args() filedata = get_filedata(args['infile']) receiver_binding = ('', args['port']) cs = init_socket(receiver_binding) send_reliable(cs, filedata, receiver_binding, args['winsize']) cs.close() print("[S] Sender finished all transmissions.")

RECIEVER

import threading import time import random import socket import argparse # Settings # Maximum chunk size used for transmission. # This value must be larger than the chunk size used in the # sender. Currently, we set this to 100. MAX_CHUNK_SIZE = 100 # dummy SEQ number used for receiver's ack packets __SEQ_UNUSED = 235347 # Loss emulation default settings. # Lose each N'th incoming packet pkt_counter_eN = 0 ack_counter_eN = 0 pkt_eN_N = 3 ack_eN_N = 4 # Lose two packets separated by one successful transmission # every M packets pkt_counter_aeM = 0 ack_counter_aeM = 0 pkt_aeM_M = 4 ack_aeM_M = 5 # IID loss with probability 1/N pkt_iid_N = 3 ack_iid_N = 4 # Default loss types pkt_losstype = 'everyN' ack_losstype = 'everyN' # Message class: we use this class to structure our protocol # message. The fields in our protocol are: # seq no: the starting sequence number of application bytes # on this packet # ack no: the cumulative ACK number of application bytes # being acknowledged in this ACK # len: the number of application bytes being transmitted on # this packet # msg: the actual application payload on this packet # The methods `serialize` and `deserialize` allow the # conversion of a protocol object to bytes transmissible # through a sendto() system call and the bytes from a # recvfrom() system call into a protocol structure. class Msg: def __init__(self, seq, ack, msg): self.seq = int(seq) self.ack = int(ack) self.msg = str(msg) self.len = len(self.msg) def serialize(self): ser_repr = (str(self.seq) + ' | ' + str(self.ack) + ' | ' + str(self.len) + ' | ' + self.msg) return ser_repr.encode('utf-8') def __str__(self): repr = "Seq: " + str(self.seq) + ' ' repr += "ACK: " + str(self.ack) + ' ' repr += "Len: " + str(self.len) + ' ' repr += "Msg: " + self.msg.strip() return repr @staticmethod def deserialize(ser_bytes_msg): ser_msg = ser_bytes_msg.decode('utf-8') parts = ser_msg.split('|') if len(parts) >= 4: return Msg(int(parts[0]), int(parts[1]), '|'.join(parts[3:])[1:]) else: print("Error in deserializing into Msg object.") exit(-1) ## Helper methods. ### Argument parsing def parse_args(): parser = argparse.ArgumentParser() parser.add_argument('--pktloss', help = "Emulated loss behavior on packets" " (default every n packets)", default = 'everyn', choices = ['noloss', 'everyn', 'alteveryn', 'iid']) parser.add_argument('--ackloss', help = "Emulated loss behavior on ACKs" " (default noloss)", default = 'noloss', choices = ['noloss', 'everyn', 'alteveryn', 'iid']) parser.add_argument('--pktlossN', type = int, default = pkt_eN_N, help = "n for pkt loss behaviors " "(only if loss specified)") parser.add_argument('--acklossN', type = int, default = ack_eN_N, help = "n for ack loss behaviors " "(only if loss specified)") parser.add_argument('--ooo_enabled', action = "store_true", dest = "ooo_enabled", help = "enable out of order data buffering (default false)") parser.add_argument('--port', type = int, help = "receiver local port to bind to (default 50007)", default = 50007) parser.add_argument('--outfile', type = str, help = "name of output file (default test-output.txt)", default = "test-output.txt") args = parser.parse_args() return vars(args) def set_loss_params(args): global pkt_losstype, ack_losstype global pkt_eN_N, pkt_aeM_M, pkt_iid_N global ack_eN_N, ack_aeM_M, ack_iid_N # Packet loss parameters pkt_losstype = args['pktloss'] pkt_lossparam = args['pktlossN'] if pkt_losstype == 'everyn': pkt_eN_N = pkt_lossparam elif pkt_losstype == 'alteveryn': if (pkt_lossparam < 4): print ("[R] Error: pktlossN must be >= 4 for alteveryn") exit(-1) pkt_aeM_M = pkt_lossparam elif pkt_losstype == 'iid': pkt_iid_N = pkt_lossparam else: assert(pkt_losstype == 'noloss') # ACK loss parameters ack_losstype = args['ackloss'] ack_lossparam = args['acklossN'] if ack_losstype == 'everyn': ack_eN_N = ack_lossparam elif ack_losstype == 'alteveryn': if (ack_lossparam < 4): print ("[R] Error: acklossN must be >= 4 for alteveryn") exit(-1) ack_aeM_M = ack_lossparam elif ack_losstype == 'iid': ack_iid_N = ack_lossparam else: assert(ack_losstype == 'noloss') ### Construct a default ACK message given an original ### message `msg`. def construct_ack(msg): ack_num = msg.seq + msg.len return Msg(__SEQ_UNUSED, ack_num, '') ### Loss emulation methods def noLoss(): return False def pkt_everyN(): global pkt_counter_eN pkt_counter_eN = (pkt_counter_eN + 1) % pkt_eN_N return pkt_counter_eN == (pkt_eN_N - 1) def ack_everyN(): global ack_counter_eN ack_counter_eN = (ack_counter_eN + 1) % ack_eN_N return ack_counter_eN == (ack_eN_N - 1) def pkt_alternateEveryM(): global pkt_counter_aeM pkt_counter_aeM = (pkt_counter_aeM + 1) % pkt_aeM_M return pkt_counter_aeM in [pkt_aeM_M - 1, pkt_aeM_M - 3] def ack_alternateEveryM(): global ack_counter_aeM ack_counter_aeM = (ack_counter_aeM + 1) % ack_aeM_M return ack_counter_aeM in [ack_aeM_M - 1, ack_aeM_M - 3] def pkt_iid(): return random.randint(1, pkt_iid_N) == 1 def ack_iid(): return random.randint(1, ack_iid_N) == 1 pkt_loss_funs = {'noloss': noLoss, 'everyn': pkt_everyN, 'alteveryn': pkt_alternateEveryM, 'iid': pkt_iid} ack_loss_funs = {'noloss': noLoss, 'everyn': ack_everyN, 'alteveryn': ack_alternateEveryM, 'iid': ack_iid} def pkt_loss_verdict(): return pkt_loss_funs[pkt_losstype]() def ack_loss_verdict(): return ack_loss_funs[ack_losstype]() ### Methods that use loss emulation while receiving packets ### or even when sending ACKs. The receiver uses these ### methods in place of the usual `recvfrom()` and `sendto()` ### to emulate the loss of packets received or ACKs sent. def lossy_recvfrom(ss, nbytes): data = None sender = None while data is None: loss = pkt_loss_verdict() if not loss: (data, sender) = ss.recvfrom(nbytes) else: # receive anyway, but discard. ss.recvfrom(nbytes) return data, sender def lossy_sendto(ss, msg, sender_addr): loss = ack_loss_verdict() if not loss: ss.sendto(msg.serialize(), sender_addr) print ("Transmitted {}".format(str(msg))) ### Init socket def init_socket(local_receiver_port): try: ss = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) print("[R]: Receiver socket created") except socket.error as err: print('socket open error: {}\n'.format(err)) exit() ss.bind(('', local_receiver_port)) return ss ### Put filedata def put_filedata(filename, filedata): print ("[R] Writing results into {}".format(filename)) f = open(filename, 'w') f.write(filedata) f.close() ############################################ # Main receive loop def receiver(ss, ooo_enabled): def get_msg_ack(): data_from_sender, sender_addr = lossy_recvfrom( ss, MAX_CHUNK_SIZE) msg = Msg.deserialize(data_from_sender) print ("Received {}".format(str(msg))) ack_msg = construct_ack(msg) return msg, ack_msg, sender_addr # Retrieve and ACK the first message. Obtain the message # length which is transmitted in this message. msg, ack_msg, sender_addr = get_msg_ack() lossy_sendto(ss, ack_msg, sender_addr) # ACK try: total_bytes = int(msg.msg) except: print ("Error: File length invalid! quitting.") ss.close() exit(-1) # Receive and ACK the subsequent (data) packets output = '' # final result of the download ooo_data = {} # out of order data buffer, only active if # ooo_enabled is set. last_seq_expected = msg.seq + len(msg.msg) + total_bytes - 1 last_acked = msg.seq + msg.len while last_acked <= last_seq_expected: msg, ack_msg, sender_addr = get_msg_ack() last_seq_in_msg = msg.seq + msg.len - 1 if last_acked == msg.seq: # Most common case: fresh in-order data # add to existing data buffer output += msg.msg new_ack_num = ack_msg.ack # Uncommon case 1: possible that previously # out-of-order data is now in order. Update # last_acked to the value that corresponds to # the "latest" in-order data, given this last # packet that appears to fill a hole in the # sequence space. if ooo_enabled: while new_ack_num in ooo_data: new_data = ooo_data[new_ack_num] output += new_data ooo_data.pop(new_ack_num) new_ack_num += len(new_data) print ("[R] Plugged a hole in seq space" " up to seq {}".format( new_ack_num)) # cumulative ACK (last_acked) must reflect # latest piece of data that is in order last_acked = new_ack_num elif last_acked < msg.seq: # Uncommon case 2: fresh data that creates a # hole in the sequence space. print ("[R] Fresh data creating seq space hole") if not ooo_enabled: output += msg.msg else: print ("[R] Sending dup ACK") ooo_data[msg.seq] = msg.msg elif last_acked > last_seq_in_msg: # Retransmitted data that receiver has already # seen. Previously sent ACKs may have been # dropped. last_acked remains unchanged. print ("[R] Spurious retransmission of data" " already at the receiver") print ("[R] Sending dup ACK") else: # partially fresh and partially retransmitted # data. We're not handling this case. print ("[R] Error: Receiver cannot handle mix of" " fresh and retransmitted data.") exit(-1) if ooo_enabled: # Use cumulative ACKs ack_msg.ack = last_acked else: # last_acked merely reflects latest data # received. This is OK for a "lossy" receiver, # but not a reliable one. last_acked = ack_msg.ack # Send the ACK if last_acked <= last_seq_expected: lossy_sendto(ss, ack_msg, sender_addr) else: # if the last ACK is dropped, handling at the # sender requires separate exchanges and # timeouts similar to TCP FIN_WAITs. Simplify # our life, don't drop the very last ACK. ss.sendto(ack_msg.serialize(), sender_addr) return output if __name__ == "__main__": args = parse_args() set_loss_params(args) ss = init_socket(args['port']) output = receiver(ss, args['ooo_enabled']) ss.close() put_filedata(args['outfile'], output) print("[R] Receiver finished downloading file data.")

Similar Samples

Explore our curated selection of programming homework samples at ProgrammingHomeworkHelp.com. These examples highlight our proficiency in Java, Python, C++, and more, demonstrating our commitment to delivering accurate and well-structured solutions. Whether you need assistance with algorithms, data structures, or software development projects, our samples showcase the quality and expertise we bring to every assignment.