×
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
Start with basic image processing concepts like color spaces and transformations. Practice simple OpenCV examples to build confidence before tackling complex tasks.
News
In 2024, the release of the 'AsyncIO Toolkit' has made asynchronous programming in Python more efficient. Similarly, 'React Quantum' introduces quantum computing concepts to JavaScript, expanding learning opportunities for students.

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.