def response(self, typ, addr, id, rtr): if self.mode == SCUMode.SendMode: raise Exception if typ == SCUPacketType.Rtr.value: header = SCUHeader() header.from_dict({ "typ": typ, "id": id, "seq": rtr, }) packet = SCUPacket() packet.from_dict({ "header": header, "payload": b'', }) self.socket.sendto(packet.raw(), addr) elif typ == SCUPacketType.Fin.value: header = SCUHeader() header.from_dict({ "typ": typ, "id": id, "seq": rtr, }) packet = SCUPacket() packet.from_dict({ "header": header, "payload": b'', }) self.socket.sendto(packet.raw(), addr)
def _sender_packet_loop(self): if self.mode == SCUMode.RecvMode: raise Exception while True: try: packet = SCUPacket() packet.from_raw(self.socket.recv(2048)) # # TODO: remove this # psuedo packet loss if random.random() >= 0.5: continue if packet.header.id not in self.connection_manager: continue if packet.header.typ == SCUPacketType.Fin.value: self.connection_manager[packet.header.id].put( (True, packet.header.seq)) elif packet.header.typ == SCUPacketType.Rtr.value: self.connection_manager[packet.header.id].put( (False, packet.header.seq)) except Exception as e: # recvが失敗した時とputが失敗した時は(適当) if e == KeyboardInterrupt: raise KeyboardInterrupt else: import traceback traceback.print_exc()
def send(self, filepath, id): # will lock the thread if self.mode == SCUMode.RecvMode: raise Exception queue = Queue() self.connection_manager[id] = queue # コネクションを登録 data_fragments = utils.split_file_into_mtu(filepath, self.mtu) all_packets = [] for (seq, df) in enumerate(data_fragments): # create header header = SCUHeader() if seq == len(data_fragments) - 1: header.from_dict({ "typ": SCUPacketType.DataEnd.value, "id": id, "seq": seq, }) else: header.from_dict({ "typ": SCUPacketType.Data.value, "id": id, "seq": seq, }) # create packet packet = SCUPacket() packet.from_dict({ "header": header, "payload": df, }) all_packets.append(packet) retransmit_seq = 0 # 再送の必要があるパケットを管理(どこまで受け取れてるか) seq = 0 while True: try: while True: try: fin, sq = queue.get(block=False) # 再送要求か受信完了報告か if fin: # 送信完了 del(self.connection_manager[id]) # コネクションを解除 return elif sq < len(all_packets): # 再送要求 retransmit_seq = max(sq, retransmit_seq) except Exception as e: # キューが空の時 if e == KeyboardInterrupt: raise KeyboardInterrupt else: break with self.lock: # 複数のsendメソッドが並列に同時実行されている可能性があるため,ロックが必要 self.socket.sendto(all_packets[seq].raw(), self.receiver_address) # パケット送信 seq = max(seq + 1, retransmit_seq) # seq更新 if seq >= len(all_packets): seq = retransmit_seq except Exception as e: # sendtoが失敗した時は(適当) if e == KeyboardInterrupt: raise KeyboardInterrupt else: import traceback traceback.print_exc()
def send(self, filepath, id): # will lock the thread if self.mode == SCUMode.RecvMode: raise Exception queue = Queue() self.connection_manager[id] = queue # Register a connection data_fragments = utils.split_file_into_mtu(filepath, self.mtu) all_packets = [] for (seq, df) in enumerate(data_fragments): # create header header = SCUHeader() if seq == len(data_fragments) - 1: header.from_dict({ "typ": SCUPacketType.DataEnd.value, "id": id, "seq": seq, }) else: header.from_dict({ "typ": SCUPacketType.Data.value, "id": id, "seq": seq, }) # create packet packet = SCUPacket() packet.from_dict({ "header": header, "payload": df, }) all_packets.append(packet) retransmit_seq = 0 # Manage packets that need to be resent (how far you can receive) seq = 0 while True: try: while True: try: fin, sq = queue.get(block=False) # Resend request or reception completion report if fin: # Finished sending del(self.connection_manager[id]) # Disconnect return elif sq < len(all_packets): # Request again retransmit_seq = max(sq, retransmit_seq) except Exception as e: # When the queue is empty if e == KeyboardInterrupt: raise KeyboardInterrupt else: break with self.lock: # Lock required as multiple send methods may be running concurrently in parallel self.socket.sendto(all_packets[seq].raw(), self.receiver_address) # Packet transmission seq = max(seq + 1, retransmit_seq) # SEQ Update if seq >= len(all_packets): seq = retransmit_seq except Exception as e: # When sendto fails (appropriate) if e == KeyboardInterrupt: raise KeyboardInterrupt else: import traceback traceback.print_exc()
def _receiver_packet_loop(self): if self.mode == SCUMode.SendMode: raise Exception received_files_flag = {} received_files_length = {} while True: try: data, from_addr = self.socket.recvfrom(2048) packet = SCUPacket() packet.from_raw(data) # TODO: remove this # psuedo packet loss if random.random() >= 0.5: continue key = utils.endpoint2str(from_addr, packet.header.id) if key not in self.received_files_data: self.received_files_data[key] = [b""] * 100 received_files_flag[key] = False if received_files_flag[key]: self.response(SCUPacketType.Fin.value, from_addr, packet.header.id, 0) continue if packet.header.typ == SCUPacketType.DataEnd.value or packet.header.typ == SCUPacketType.Data.value: if packet.header.typ == SCUPacketType.DataEnd.value: received_files_length[key] = packet.header.seq + 1 self.received_files_data[key][ packet.header.seq] = packet.payload rtr = self.calculate_rtr(key, packet.header.seq) if rtr is not None: # 再送要求する必要あり self.response(SCUPacketType.Rtr.value, from_addr, packet.header.id, rtr) elif key in received_files_length and self.is_all_received( key, received_files_length[key]): # ファイル受信完了 received_files_flag[key] = True self.response(SCUPacketType.Fin.value, from_addr, packet.header.id, 0) self.file_received.put( (key, received_files_length[key])) except Exception as e: # recvが失敗した時とputが失敗した時は(適当) if e == KeyboardInterrupt: raise KeyboardInterrupt else: import traceback traceback.print_exc()
def _receiver_packet_loop(self): if self.mode == SCUMode.SendMode: raise Exception received_files_flag = {} received_files_length = {} while True: try: data, from_addr = self.socket.recvfrom(2048) packet = SCUPacket() packet.from_raw(data) key = utils.endpoint2str(from_addr, packet.header.id) if key not in self.received_files_data: self.received_files_data[key] = [b""] * 100 received_files_flag[key] = False if received_files_flag[key]: self.response(SCUPacketType.Fin.value, from_addr, packet.header.id, 0) continue if packet.header.typ == SCUPacketType.DataEnd.value or packet.header.typ == SCUPacketType.Data.value: if packet.header.typ == SCUPacketType.DataEnd.value: received_files_length[key] = packet.header.seq + 1 self.received_files_data[key][ packet.header.seq] = packet.payload rtr = self.calculate_rtr(key, packet.header.seq) if rtr is not None: # Need to send retransmission request self.response(SCUPacketType.Rtr.value, from_addr, packet.header.id, rtr) elif key in received_files_length and self.is_all_received( key, received_files_length[key]): # Received file: received_files_flag[key] = True self.response(SCUPacketType.Fin.value, from_addr, packet.header.id, 0) self.file_received.put( (key, received_files_length[key])) except Exception as e: # When recv or put failed: if e == KeyboardInterrupt: raise KeyboardInterrupt else: import traceback traceback.print_exc()
def _sender_packet_loop(self): if self.mode == SCUMode.RecvMode: raise Exception while True: try: packet = SCUPacket() packet.from_raw(self.socket.recv(2048)) if packet.header.id not in self.connection_manager: continue if packet.header.typ == SCUPacketType.Fin.value: self.connection_manager[packet.header.id].put((True, packet.header.seq)) elif packet.header.typ == SCUPacketType.Rtr.value: self.connection_manager[packet.header.id].put((False, packet.header.seq)) except Exception as e: # When recv fails and when put fails (appropriate) if e == KeyboardInterrupt: raise KeyboardInterrupt else: import traceback traceback.print_exc()
def _sender_packet_loop(self): prev_packet = SCUPacket() while True: try: packet = SCUPacket() packet.from_raw(self.socket.recv(2048)) # # psuedo packet loss TODO: remove # if random.random() >= 0.5: # continue if packet.header.id not in self.connection_manager: continue if prev_packet.header.__dict__ == packet.__dict__: continue prev_packet = packet self.connection_manager[packet.header.id].put(packet) except Exception as e: # recvが失敗した時とputが失敗した時は(適当) if e == KeyboardInterrupt: raise KeyboardInterrupt else: import traceback traceback.print_exc()
def _receiver_packet_loop(self): prev_packet = SCUPacket() while True: try: data, from_addr = self.socket.recvfrom(2048) # # # TODO: remove this # # psuedo packet loss # if random.random() >= 0.5: # continue packet = SCUPacket() packet.from_raw(data) if prev_packet.__dict__ == packet.__dict__: continue prev_packet = packet self.task_manager.put((packet, from_addr)) except Exception as e: if e == KeyboardInterrupt: raise KeyboardInterrupt else: import traceback traceback.print_exc()
def response(self, typ, addr, key, seq, resendID, content=b""): """ responses a single packet of retry, or fin. it can be used to just send packets. """ if self.mode == SCUMode.SendMode: raise Exception header = SCUHeader() packet = SCUPacket() header.from_dict({ "typ": typ, "id": key, "seq": seq, "resendID": resendID }) if typ == SCUPacketType.Rtr.value: packet.from_dict({"header": header, "payload": content.encode()}) elif typ == SCUPacketType.Fin.value: packet.from_dict({"header": header, "payload": b''}) else: raise Exception() self.socket.sendto(packet.raw(), addr)
def send(self, filepath, fileno): if self.mode == SCUMode.RecvMode: raise Exception queue = Queue() self.connection_manager[fileno] = queue # register queue data_fragments = utils.split_file_into_mtu(filepath, self.mtu) all_packets = [] current_resendID = 0 for (seq, df) in enumerate(data_fragments): header = SCUHeader() if seq == len(data_fragments) - 1: header.from_dict({ "typ": SCUPacketType.DataEnd.value, "id": fileno, "seq": seq, "resendID": 0 }) else: header.from_dict({ "typ": SCUPacketType.Data.value, "id": fileno, "seq": seq, "resendID": 0 }) packet = SCUPacket() packet.from_dict({"header": header, "payload": df}) all_packets.append(packet) while True: # main loop if self.send_mode == SendMode.SendNewFile: for seq in range(len(all_packets) - 1): with self.lock: self.socket.sendto(all_packets[seq].raw(), self.receiver_address) # for seq in range(len(all_packets) - 1): # with self.lock: # self.socket.sendto(all_packets[seq].raw(), self.receiver_address) self.send_mode = SendMode.KeepSendingDataEndUntilResendReqComes elif self.send_mode == SendMode.KeepSendingDataEndUntilResendReqComes: dataEnd = all_packets[-1] dataEnd.header.resendID = 0 while True: if random.random() >= 0.8: with self.lock: self.socket.sendto(dataEnd.raw(), self.receiver_address) try: packet = queue.get(block=False) except Exception as e: if e == KeyboardInterrupt: raise KeyboardInterrupt else: pass else: if packet.header.typ == SCUPacketType.Rtr.value and packet.header.resendID >= 1: current_resendID = packet.header.resendID self.missing_seqs_str = packet.payload.decode() self.send_mode = SendMode.SendMissingSeqs break elif packet.header.typ == SCUPacketType.Fin.value: return elif self.send_mode == SendMode.SendMissingSeqs: missing_seqs = list(map(int, self.missing_seqs_str.split(","))) # 言われてた欠損ファイルを一回送る、それか二周送る for i in range(len(missing_seqs) - 1): data = all_packets[missing_seqs[i]] data.header.resendID = current_resendID with self.lock: self.socket.sendto(data.raw(), self.receiver_address) end_packet = all_packets[missing_seqs[-1]] end_packet.header.resendID = current_resendID end_packet.header.typ = SCUPacketType.End.value self.end_packet = end_packet self.send_mode = SendMode.KeepSendingEndUntilResendReqComes elif self.send_mode == SendMode.KeepSendingEndUntilResendReqComes: while True: if random.random() >= 0.9: with self.lock: self.socket.sendto(self.end_packet.raw(), self.receiver_address) try: packet = self.connection_manager[fileno].get( block=False) except Exception as e: # queue is empty if e == KeyboardInterrupt: raise KeyboardInterrupt else: pass else: if packet.header.typ == SCUPacketType.Rtr.value and packet.header.resendID > current_resendID: current_resendID = packet.header.resendID self.missing_seqs_str = packet.payload.decode() missing_seqs_count = len( self.missing_seqs_str.split(',')) if missing_seqs_count <= n: self.send_mode = SendMode.SendingMissingSeqLoopUntilFinComes break else: self.send_mode = SendMode.SendMissingSeqs break elif packet.header.typ == SCUPacketType.Fin.value: return elif self.send_mode == SendMode.SendingMissingSeqLoopUntilFinComes: index = 0 remained_seqs = list(map(int, self.missing_seqs_str.split(','))) while True: data = all_packets[remained_seqs[index]] data.header.resendID = current_resendID with self.lock: # lock self.socket.sendto(data.raw(), self.receiver_address) if index == len(remained_seqs) - 1: index = 0 else: index += 1 try: packet = self.connection_manager[fileno].get( block=False) except Exception as e: if e == KeyboardInterrupt: raise KeyboardInterrupt else: continue else: if packet.header.typ == SCUPacketType.Fin.value: del (self.connection_manager[fileno]) self.send_mode = SendMode.SendNewFile return else: raise Exception
def send(self, filepath, id): # Will lock the thread if self.mode == SCUMode.RecvMode: raise Exception queue = Queue() self.connection_manager[id] = queue # Register the connection data_fragments = utils.split_file_into_mtu(filepath, self.mtu) all_packets = [] for (seq, df) in enumerate(data_fragments): # create header header = SCUHeader() if seq == len(data_fragments) - 1: header.from_dict({ "typ": SCUPacketType.DataEnd.value, "id": id, "seq": seq, }) else: header.from_dict({ "typ": SCUPacketType.Data.value, "id": id, "seq": seq, }) # create packet packet = SCUPacket() packet.from_dict({ "header": header, "payload": df, }) all_packets.append(packet) retransmit_seq = 0 # Manage the packets which needs retransmission (how much is it received correctly) seq = 0 while True: try: while True: try: fin, sq = queue.get( block=False ) # Retransmission Request or Transmission Done Report if fin: # 送信完了 del (self.connection_manager[id] ) # Remove connection return elif sq < len(all_packets): # Retransmission Request retransmit_seq = max(sq, retransmit_seq) except Exception as e: # When queue is empty: if e == KeyboardInterrupt: raise KeyboardInterrupt else: break with self.lock: # Multiple send method might be running in parallel, so lock is required. self.socket.sendto(all_packets[seq].raw(), self.receiver_address) # Send packet seq = max(seq + 1, retransmit_seq) # Update seq if seq >= len(all_packets): seq = retransmit_seq except Exception as e: # When sendto has failed: if e == KeyboardInterrupt: raise KeyboardInterrupt else: import traceback traceback.print_exc()