def recvfile(self): filename = self.fileInfo["filename"] filesize = self.fileInfo["filesize"] self.recv_base = 0 # 当前窗口基序号 self.N = 1000 # 窗口大小 self.window = [] # 接收方窗口 for i in range(self.N): self.window.append(None) recvsize = 0 # 已接收数据大小 log_info("开始接收文件 %s" % (filename)) self.myMainWindow.emitReceiveMessage( str(self.client_addr) + ":\n开始接收文件 %s" % (filename)) with open(filename, 'wb') as f: # pbar = ProgressBar().start() while True: try: message, addr = self.udpServer.recvfrom(self.bufferSize) except Exception as e: print(self.port, e) if (recvsize == filesize): # pbar.finish() log_info("接收完毕,断开连接") self.myMainWindow.emitReceiveMessage( str(self.client_addr) + ":\n接收完毕,断开连接") else: log_error("连接已断开") self.myMainWindow.emitReceiveMessage( str(self.client_addr) + ":\n连接已断开") break message = LFTPMessage.unpack(message) seqnum = message.seqnum content = message.content content_size = message.content_size if (seqnum >= self.recv_base and seqnum < self.recv_base + self.N): self.window[seqnum - self.recv_base] = content[:content_size] while self.window[0] != None: f.write(self.window[0]) recvsize += len(self.window[0]) #pbar.update(int(recvsize / filesize * 100)) self.window.pop(0) self.window.append(None) self.recv_base += 1 rwnd = 0 for item in self.window: if item == None: rwnd += 1 response = LFTPMessage(ACK=1, seqnum=seqnum, rwnd=rwnd, acknum=self.recv_base) if (seqnum <= self.recv_base + self.N): self.udpServer.sendto(response.pack(), addr)
def handshake(self): log_info("等待连接中") self.udpServer.settimeout(3) while True: try: message, self.client_addr = self.udpServer.recvfrom( self.bufferSize) except Exception as e: log_error("客户连接断开,超时关闭,当前端口:", self.port) self.state = State.CLOSED break message = LFTPMessage.unpack(message) if self.state == State.LISTEN: if message.SYN == 1: log_info("收到第一次握手报文", self.client_addr) self.client_isn = message.seqnum res = LFTPMessage(SYN=1, ACK=1, seqnum=self.server_isn, acknum=self.client_isn + 1) self.fileInfo = json.loads( message.content[:message.content_size].decode("utf-8")) if self.fileInfo["LFTPType"] == "UPLOAD": res.content = message.content elif self.fileInfo["LFTPType"] == "DOWNLOAD": try: self.fileInfo["filesize"] = os.path.getsize( self.fileInfo["filename"]) except Exception as e: log_error("对应文件已丢失,无法提供下载:", self.fileInfo["filename"]) self.fileInfo["filesize"] = -1 res.content = json.dumps( self.fileInfo).encode("utf-8") res.content_size = len(res.content) self.udpServer.sendto(res.pack(), self.client_addr) return res.content = json.dumps(self.fileInfo).encode("utf-8") res.content_size = len(res.content) self.udpServer.sendto(res.pack(), self.client_addr) self.state = State.SYN_RCVN threading.Timer(1, self.handshakeTimer, [self.state]).start() log_info("发送第二次握手报文", self.client_addr) elif self.state == State.SYN_RCVN: if message.SYN == 0 and message.ACK == 1 and message.seqnum == self.client_isn + 1 and message.acknum == self.server_isn + 1: self.state = State.ESTABLISHED log_info("收到第三次握手报文", self.client_addr) log_info("建立连接成功", self.client_addr) break
def TimeOutAndReSend(self): self.lock.acquire() self.ssthresh = self.cwnd/2 self.cwnd = 1 seqnum = self.send_window.send_base content = self.send_window.getContentBySeqnum(seqnum) self.lock.release() if content == None: return # log_warn("超时重传:", seqnum) message = LFTPMessage(seqnum=seqnum, content_size=len(content), content=content) self.udpClient.sendto(message.pack(), (self.host, self.port)) self.timer.cancel() self.timer = threading.Timer(self.timer.interval*2, self.TimeOutAndReSend) self.timer.start()
def ControlHandShake(self): self.serverList = [] self.base_port = 9000 self.max_port = 9099 for port in range(self.base_port, self.max_port): self.serverList.append(None) while self.servering: try: log_info("等待用户连接传入") message, addr = self.udpServer.recvfrom(self.bufferSize) log_info(addr) message = LFTPMessage.unpack(message) log_info("getport:", message.getport) print(message) if message.getport == 1: for port in range(self.base_port, self.max_port): if self.serverList[ port - self.base_port] == None or self.serverList[ port - self.base_port].state == State.CLOSED: log_info("用户连接传入,分配端口:", port) self.serverList[port - self.base_port] = LFTPserver( server_type='data', host='', port=port, bufferSize=2048, myMainWindow=self.myMainWindow) self.servering_thread = threading.Thread( target=self.ServerRun, args=(self.serverList[port - self.base_port], )) self.servering_thread.start() content = {"port": port} content = json.dumps(content).encode("utf-8") resp = LFTPMessage(getport=1, content_size=len(content), content=content) self.udpServer.sendto(resp.pack(), addr) break except Exception as ret: msg = 'file server 接收失败\n' time.sleep(0.1) print(msg) break
def ControlHandShake(self): con_time = 0 self.udpClient.settimeout(2) while True: # 发送请求获取分配端口 request = LFTPMessage(getport=1) request.getport = 1 self.udpClient.sendto(request.pack(), (self.host, self.port)) try: message = self.udpClient.recv(2048) except Exception as e: con_time += 1 if con_time == 10: log_error("连接失败,网络/服务端故障") return False log_warn("连接超时, 重新连接中, 连接次数: ", con_time) continue message = LFTPMessage.unpack(message) if message.getport == 1: data = json.loads(message.content[:message.content_size].decode("utf-8")) self.port = data["port"] return True
def handshake(self, LFTPType, filename, filesize = 0): log_info("开始连接服务器") self.fileInfo = { "filename": filename, "filesize": filesize, "LFTPType": LFTPType } fileInfojson = json.dumps(self.fileInfo).encode("utf-8") message = LFTPMessage(SYN=1, seqnum=self.client_isn, content_size=len(fileInfojson), content=fileInfojson) self.udpClient.sendto(message.pack(), (self.host, self.port)) self.state = State.SYN_SEND threading.Timer(0.2, self.handshakeTimer, [self.state, message, 0]).start() log_info("发送第一次握手报文") while True: try: res = self.udpClient.recv(2048) except Exception as e: log_warn("接收回应报文超时") if self.state == State.CLOSED: log_error("连接失败") break continue res = LFTPMessage.unpack(res) if self.state == State.SYN_SEND and res.SYN == 1 and res.ACK == 1 and res.acknum == self.client_isn+1: log_info("收到第二次握手响应报文") if self.fileInfo["LFTPType"] == "DOWNLOAD": self.fileInfo = json.loads(res.content[:res.content_size].decode("utf-8")) if self.fileInfo["filesize"] == -1: log_error("文件不存在,无法提供下载:", self.fileInfo["filename"]) self.state = State.CLOSED return self.server_isn = res.seqnum reply_message = LFTPMessage(SYN=0, ACK=1, seqnum=self.client_isn+1, acknum=self.server_isn+1) self.udpClient.sendto(reply_message.pack(), (self.host, self.port)) self.state = State.ESTABLISHED log_info("发送第三次握手报文") log_info("连接建立完毕") break
def recvACK(self, filesize): while True: self.lock.acquire() if self.send_window.isEmpty() == False: item = self.send_window.getItemToSend() if item != None: self.lock.release() break self.lock.release() first_message = LFTPMessage(seqnum=item.seqnum, content_size=len(item.content), content=item.content) self.udpServer.sendto(first_message.pack(), self.client_addr) # 设置超时定时器 self.timer = threading.Timer(self.TimeoutInterval, self.TimeOutAndReSend) self.timer.start() recvSize = 0 while (True): # 接收信息 try: message = self.udpServer.recv(2048) except Exception as e: if filesize == recvSize: # pbar.finish() log_info("服务端接收完毕") self.timer.cancel() else: self.timer.cancel() log_error("超时重连失败") break message = LFTPMessage.unpack(message) acknum = message.acknum self.lock.acquire() # 更新滑动窗口 if self.cwnd < self.ssthresh: self.cwnd += 1 else: self.cwnd += 1 / int(self.cwnd) # 更新rwnd self.send_window.ACKseqnum(acknum) self.rwnd = message.rwnd self.send_window.rwnd = message.rwnd log_info("rwnd: ", self.rwnd, ", cwnd: ", self.cwnd) # 确认一波 log_info(acknum, " ACKTIME: ", self.send_window.getACKTimeBySeqnum(acknum)) if self.send_window.getACKTimeBySeqnum(acknum) == 4: # 三次冗余进行重传,同时更新cwnd和ssthresh log_warn("三次冗余", acknum) self.ssthresh = self.cwnd / 2 self.cwnd = self.cwnd / 2 + 3 r_content = self.send_window.getContentBySeqnum(acknum) r_message = LFTPMessage(seqnum=acknum, content_size=len(r_content), content=r_content) self.udpServer.sendto(r_message.pack(), self.client_addr) # 重新设置超时定时器 self.timer.cancel() self.timer = threading.Timer(self.TimeoutInterval, self.TimeOutAndReSend) self.timer.start() elif self.send_window.getACKTimeBySeqnum(acknum) == 1: # 首次接收到,send_base改变 recvSize += self.send_window.updateSendBase(acknum) List = self.send_window.getSendList(self.cwnd) for item in List: message = LFTPMessage(seqnum=item.seqnum, content_size=len(item.content), content=item.content) self.udpServer.sendto(message.pack(), self.client_addr) # 重新设置超时定时器 self.timer.cancel() self.timer = threading.Timer(self.TimeoutInterval, self.TimeOutAndReSend) self.timer.start() elif self.send_window.getACKTimeBySeqnum(acknum) == -1: log_info("服务端接收完毕") self.timer.cancel() break self.lock.release() # print(recvSize + "/" + filesize,'\r') # pbar.update(int(recvSize/filesize)*100) if filesize == recvSize: #pbar.finish() log_info("服务端接收完毕") self.timer.cancel() break
def DownloadFile(self, filename): # 发起握手建立连接 self.handshake("DOWNLOAD", filename) # 握手完毕未进入连接建立状态,退出 if self.state != State.ESTABLISHED: log_error("连接建立失败,无法下载文件") self.state = State.CLOSED return filename = self.fileInfo["filename"] filesize = self.fileInfo["filesize"] self.recv_base = 0 # 当前窗口基序号 self.N = 1000 # 窗口大小 self.window = [] # 接收方窗口 for i in range(self.N): self.window.append(None) self.origin_time = time.time() self.last_time = time.time() self.last_recvsize = 0 self.compute_result = 0 self.total_result = 0 recvsize = 0 # 已接收数据大小 log_info("开始接收文件 %s"%(filename)) with open(filename, 'wb') as f: # pbar = ProgressBar().start() self.udpClient.settimeout(2) while True: try: message = self.udpClient.recv(2048) except Exception as e: if (recvsize == filesize): # pbar.finish() log_info("接收完毕,断开连接") else: log_error("连接已断开") break message = LFTPMessage.unpack(message) seqnum = message.seqnum content = message.content content_size = message.content_size if (seqnum >= self.recv_base and seqnum < self.recv_base + self.N): self.window[seqnum - self.recv_base] = content[:content_size] while self.window[0] != None: f.write(self.window[0]) recvsize += len(self.window[0]) # pbar.update(int(recvsize / filesize * 100)) self.DownLoadProgress(recvsize, filesize) self.window.pop(0) self.window.append(None) self.recv_base += 1 rwnd = 0 for item in self.window: if item == None: rwnd += 1 response = LFTPMessage(ACK=1, seqnum=seqnum, rwnd=rwnd, acknum=self.recv_base) if (seqnum <= self.recv_base + self.N): self.udpClient.sendto(response.pack(), (self.host, self.port))
def recvACK(self, filesize): # pbar = ProgressBar().start() # 发送第一个数据报文,此时cwnd = 1 self.cwnd = 1 while True: self.lock.acquire() if self.send_window.isEmpty() == False: item = self.send_window.getItemToSend() if item != None: self.lock.release() break self.lock.release() first_message = LFTPMessage(seqnum=item.seqnum, content_size=len(item.content), content=item.content) self.udpClient.sendto(first_message.pack(), (self.host, self.port)) # 设置超时定时器 self.timer = threading.Timer(self.TimeoutInterval, self.TimeOutAndReSend) self.timer.start() self.origin_time = time.time() self.last_time = time.time() self.last_recvsize = 0 self.compute_result = 0 self.total_result = 0 recvSize = 0 while(True): # 接收信息 try: message = self.udpClient.recv(2048) except Exception as e: if filesize == recvSize: # pbar.finish() log_info("服务端接收完毕") self.timer.cancel() else: log_error("超时重连失败") self.timer.cancel() break message = LFTPMessage.unpack(message) acknum = message.acknum self.lock.acquire() # 更新滑动窗口 if self.cwnd < self.ssthresh: self.cwnd += 1 else: self.cwnd += 1/int(self.cwnd) # 更新rwnd self.send_window.ACKseqnum(acknum) self.rwnd = message.rwnd self.send_window.rwnd = message.rwnd # log_info("rwnd: ", self.rwnd, ", cwnd: ", self.cwnd) # # 确认一波 # log_info(acknum, " ACKTIME: ",self.send_window.getACKTimeBySeqnum(acknum)) if self.send_window.getACKTimeBySeqnum(acknum) == 4: # 三次冗余进行重传,同时更新cwnd和ssthresh # log_warn("三次冗余", acknum) self.ssthresh = self.cwnd/2 self.cwnd = self.cwnd/2+3 r_content = self.send_window.getContentBySeqnum(acknum) r_message = LFTPMessage(seqnum=acknum, content_size=len(r_content), content=r_content) self.udpClient.sendto(r_message.pack(), (self.host, self.port)) # 重新设置超时定时器 self.timer.cancel() self.timer = threading.Timer(self.TimeoutInterval, self.TimeOutAndReSend) self.timer.start() elif self.send_window.getACKTimeBySeqnum(acknum) == 1: # 首次接收到,send_base改变 recvSize += self.send_window.updateSendBase(acknum) List = self.send_window.getSendList(self.cwnd) for item in List: message = LFTPMessage(seqnum=item.seqnum, content_size=len(item.content), content=item.content) self.udpClient.sendto(message.pack(), (self.host, self.port)) # 重新设置超时定时器 self.timer.cancel() self.timer = threading.Timer(self.TimeoutInterval, self.TimeOutAndReSend) self.timer.start() elif self.send_window.getACKTimeBySeqnum(acknum) == -1: recvSize = filesize self.UpLoadProgress(recvSize, filesize) log_info("服务端接收完毕") self.timer.cancel() self.lock.release() break self.lock.release() self.UpLoadProgress(recvSize, filesize) # pbar.update(int(recvSize/filesize)*100) if filesize == recvSize: # pbar.finish() log_info("服务端接收完毕") self.timer.cancel() break