Пример #1
0
    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)
Пример #2
0
 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
Пример #3
0
 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()
Пример #4
0
 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
Пример #5
0
 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
Пример #6
0
    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
Пример #7
0
    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
Пример #8
0
    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))
Пример #9
0
    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