使用socketserver進行多用戶的文件傳輸
服務端
class FtpServer(socketserver.BaseRequestHandler): # 繼承socketserver.BaseRequestHandler
def handle(self): #handle必須有,是派生方法是重定義繼承的handle,是用於處理交互
pass
客服端
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((HOST, PORT)) # 建立連接
開啟服務
server = socketserver.ThreadingTCPServer((HOST, PORT), FtpServer) # 創建socketserver對象
server.serve_forever() # 開啟服務(一直開啟)
handle
def handle(self): """處理與用戶的命令""" while self: """用於解決黏包問題""" header_size = struct.unpack('i', self.request.recv(4))[0] # 接收自定義包頭 header_bytes = self.request.recv(header_size) header = json.loads(header_bytes.decode('utf-8')) action_type = header.get('type') """"用反射調用方法""" if hasattr(self, '_' + action_type): getattr(self, '_' + action_type)(header) else: print('invalid command')
服務端自定義的發送包頭
def _send(self, status_code, **kwargs): msg = kwargs msg['status_code'] = status_code msg['status_msg'] = self.STATUS_CODE[status_code] bytes_data = json.dumps(msg).encode('utf-8') self.request.send(struct.pack('i', len(bytes_data))) self.request.send(bytes_data)
服務端轉到客服端
def _get(self, header): filename = header.get('filename') if os.path.isfile(file_path): file_size = os.stat(filename ).st_size self._send(size=file_size) # 先發送包頭 print("ready to send file ") f = open(file_path, 'rb') for line in f: self.request.send(line) else: print('file send done..', filename ) f.close() else: self_send(size=0)
客戶端接收
def get(filename): _send(type='get', filename=filename) # 發送自定義頭 header = _recv() # 接收自定義頭 size = header.get('size') if size: f = open(filename, 'wb') while size: # 接收數據 if size >= 1024: data = sock.recv(1024) f.write(data) f.flush() size -= len(data) # len(data)為接收到的數據長度,如果寫1024的話可能會出現數據接收不完整的問題 else: data = sock.recv(size) f.write(data) f.flush() size -= len(data) # 同理 if size == 0: break f.close()
客服端包頭的發送和接收
def _send(**kwargs): """發送""" msg = kwargs header_bytes = json.dumps(msg).encode('utf-8') sock.send(struct.pack('i', len(header_bytes))) sock.send(header_bytes) def _recv(): """接收""" header_size = struct.unpack('i', sock.recv(4))[0] header_bytes = sock.recv(header_size) header = json.loads(header_bytes.decode('utf-8')) return header