def __init__(self, port: int, host: str): """initialize sender (client) Arguments: port {int} -- port number of the server(receiver) host {str} -- hostnamse of the server """ Rudp.__init__(self, port, host) self.server = (self.host, self.port) self.socket.settimeout(RudpSender.timeout)
def goBackNSend(self, f): """GBN file sending method Arguments: f {file} -- (opened) readable binary file """ size = Rudp.getFileSize(f) log.info("File Size: " + str(size)) self.stopAndWaitSendData(Rudp.signature.encode()) self.stopAndWaitSendData(str(size).encode()) # a list holding on-flight packets sendList = [] # indicates the end of file readEnd = False # store recent acks for congestion control ackList = [] while (not readEnd) or (len(sendList)): # fill sendList packetToFill = RudpSender.sendWindow - len(sendList) if packetToFill > 0: for i in range(packetToFill): data = self.__readNext(f) if data: p = self.send(data) print("Packet Seq: ", p.seq, " Added to Send List") sendList.append(p) else: readEnd = True # try to receive ack try: while len(sendList): ack = self.acknowledge() print("Ack Received: ", ack) self.mark(sendList, ack) ackList.append(ack) self.checkDupAcks(ackList) sendList = Rudp.cleanPacketList(sendList) except socket.timeout: print("Timeout") self.resendPackets(sendList) if RudpSender.enableCongestionControl: self.congestionControl(RudpSender.LossEvent.Timeout) except RudpSender.DupAcks: print("Dupacks") ackList = [] self.resendPackets(sendList) if RudpSender.enableCongestionControl: self.congestionControl(RudpSender.LossEvent.DupAcks) else: if RudpSender.enableCongestionControl: self.congestionControl(RudpSender.LossEvent.NoLoss)
def recvData(self) -> bytes: """receive from socket and return the content and acknowledge the packet used in stop and wait Returns: bytes -- Rudp.Packet.payload """ packet = self.recvPacket() if (packet.seq == Rudp.ackPlusOne(self.ack)): self.ack = Rudp.ackPlusOne(self.ack) self.acknowledgePacket(packet) return packet.payload else: return None
def acknowledge(self, sequence: int): """send packet acknowledging a sequence number to the client Arguments: sequence {int} -- sequence # """ ackPacket = Rudp.Packet(self.seq, sequence) frame = ackPacket.construct() self.seqPlusOne() self.socket.sendto(frame, self.client)
def __init__(self, port: int): """initialize receiver Arguments: port {int} -- port number to bind on local server """ Rudp.__init__(self, p=port) self.client = None self.ack = None # for testing on server self.host = "10.10.2.10" # for local test # self.host = "127.0.0.1" # host = socket.gethostname() # self.host = socket.gethostbyname(host) try: print(self.host, self.port) self.socket.bind((self.host, self.port)) except Exception as e: print("Cannot bind port: ", self.port, ". Because:", format(e))
def send(self, data: bytes): """warp a packet for data and send this Arguments: data {bytes} -- data to send """ packet = Rudp.Packet(self.seq, 0, data) packet.timesamp = time() self.sendPacket(packet) self.seqPlusOne() return (packet)
def goBackNRecv(self, f): """GBN file receiving method Arguments: f {_io.TextIOWrapper} -- (opened) file to write """ self.listen() size = self.getSize() # cache for incoming packets recvList = [] while True: try: recvPacket = self.recvPacket() print("Packet Seq: ", recvPacket.seq, " Received") recvList = self.insertOrderedPacket(recvPacket, recvList) except (Rudp.InvalidPacket, Rudp.WrongClient): pass # ack consecutive packets and write to file for packet in recvList: if packet.seq == Rudp.ackPlusOne(self.ack): self.acknowledge(packet.seq) self.ack = Rudp.ackPlusOne(self.ack) f.write(packet.payload) f.flush() packet.status = False print("Packet Seq: ", packet.seq, " Acked and Written") else: self.acknowledge(self.ack) if not len(recvList): self.acknowledge(self.ack) # drop acked files self.cleanPacketList(recvList) if Rudp.getFileSize(f) == size: f.close() log.info("Transmission Complete, exit...") break
def stopAndWaitRecv(self, f): """stop-and-wait file receiving method Arguments: f {_io.TextIOWrapper} -- (opened) file to save """ self.listen() size = self.getSize() while True: try: data = self.recvData() except Exception as e: print(format(e)) if data: f.write(data) f.flush() print("file size: ", Rudp.getFileSize(f)) if Rudp.getFileSize(f) == size: f.close() log.info("Transmission Complete, exit...") break
def recvPacket(self) -> Rudp.Packet: """receive a valid packet from the client Raises: Rudp.WrongClient: the address of the client doesn't corresponds to self.client Returns: Rudp.Packet -- received packet """ (packet, validity, c) = self.recv() if (c != self.client): raise Rudp.WrongClient("Wrong Package from " + c) return packet
def recv(self) -> tuple: """receive raw data from socket and check the validity by checksum Raises: Rudp.InvalidPacket: checksum doesn't match the packet's data Returns: tuple -- (Rudp.Packet, validity: bool, client:(ip addr, port)) """ (data, c) = self.socket.recvfrom(Rudp.Packet.buffer()) # print(data) (packet, validity) = Rudp.Packet.unpack(data) if (validity): print("Valid Packet Received From: ", c) else: raise Rudp.InvalidPacket("Invalid Packet Received") return (packet, validity, c)
def stopAndWaitSend(self, f): """stop-and-wait file sending method Arguments: f {file} -- (opened) readable binary file to send """ size = Rudp.getFileSize(f) log.info("File Size: " + str(size)) self.stopAndWaitSendData(Rudp.signature.encode()) self.stopAndWaitSendData(str(size).encode()) while True: data = self.__readNext(f) if data: self.stopAndWaitSendData(data) else: break
def cleanPacketList(self, packets: list) -> list: result = Rudp.cleanPacketList(packets) for p in result: if p.seq <= self.ack: result.remove(p) return result