Python Socket加密聊天程序文件传输功能报错及加密方案求助
报错根因
你碰到的clientSocket.send(l)报错核心是服务端提前断开了连接:客户端发完加密的/filetransfer指令后直接发原始二进制文件内容,服务端的handle_client线程还在按文本逻辑尝试解密收到的二进制内容,解密失败直接触发异常断开连接,客户端再往已经关闭的连接发数据就会报错。
除此之外你还存在线程逻辑冲突、文件未加密、转发逻辑错误三个核心问题,以下是完整修复方案:
客户端修改
1. 修复发送线程逻辑
不要重复开启sndChat线程,避免多个线程同时写同一个socket引发冲突,文件发送完成后继续保持聊天即可:
def sndChat(self): while True: message = input('') if message == '/filetransfer': # 先发送加密的传输指令 enc_msg = self.aes.encrypt(message) clientSocket.send(enc_msg) # 直接调用文件发送方法 self.sndFile() continue # 普通文本消息正常加密发送 enc_msg = self.aes.encrypt(message) clientSocket.send(enc_msg)
2. 新增文件加密逻辑
读文件后先加密再发送,最后加结束标记告知接收端文件传输完成:
def sndFile(self): print("---File Transfer---") filename = 'C:\\Users\\USER\\Desktop\\filetest\\test.txt' if not exists(filename): print("文件不存在") return f = open(filename,'rb') print('Sending...') # 缓冲区大小和文本消息保持一致,避免解密错位 l = f.read(4096) while l: # 先加密文件块再发送 enc_block = self.aes.encrypt(l) clientSocket.send(enc_block) l = f.read(4096) f.close() # 发送结束标记 end_flag = self.aes.encrypt(b'FILE_TRANSFER_END') clientSocket.send(end_flag) print('文件发送完成')
3. 修复接收线程逻辑
收到文件传输通知后直接调用接收方法,不要开启多余线程导致阻塞:
def rcvChat(self): print("\nWelcome to Chatee!") while True: try: raw_data = clientSocket.recv(4096) message = self.aes.decrypt(raw_data) if message == 'filetransfer start': print("收到文件传输请求,开始接收文件") self.rcvFile() continue # 普通消息正常打印 print(message.decode(encodeType)) except: break
4. 修复文件接收逻辑
收到结束标记就停止接收,避免无限等待:
def rcvFile(self): filename = 'received.txt' f = open(filename,'wb') print('Receiving...') while True: raw_data = clientSocket.recv(4096) dec_data = self.aes.decrypt(raw_data) # 匹配到结束标记就退出循环 if dec_data == b'FILE_TRANSFER_END': break f.write(dec_data) f.close() print('文件接收完成,已保存为received.txt')
服务端修改
1. 修复客户端处理逻辑
收到文件传输指令后不要join转发线程,避免阻塞当前客户端的其他消息处理:
if msg == '/filetransfer': # 给所有客户端广播文件传输开始通知 self.broadcast('filetransfer start') thread = threading.Thread(target=self.sndFile, args=(client, )) thread.daemon = True thread.start() # 删掉原来的thread.join(),否则会卡住整个处理线程
2. 修复文件转发和加密逻辑
不要覆盖发送端client变量,转发时给每个接收端用独立的DH协商密钥加密:
def sndFile(self, sender_client): print("---开始转发文件---") # 先初始化发送端的AES解密器 sender_aes = AESCipher(self.client_keys[sender_client]) while True: try: raw_block = sender_client.recv(4096) if not raw_block: break # 先解密拿到原始文件块 dec_block = sender_aes.decrypt(raw_block) # 匹配结束标记,转发给所有接收端 if dec_block == b'FILE_TRANSFER_END': for client in self.clients: if client == sender_client: continue recv_aes = AESCipher(self.client_keys[client]) enc_end = recv_aes.encrypt(b'FILE_TRANSFER_END') client.send(enc_end) break # 给每个接收端用对应密钥加密后转发 for client in self.clients: if client == sender_client: continue recv_aes = AESCipher(self.client_keys[client]) enc_block = recv_aes.encrypt(dec_block) client.send(enc_block) except Exception as e: print(f'文件转发失败: {e}') break print("文件转发完成")
以上修改已经自动适配了你现有的Diffie-Hellman密钥协商和AES加密逻辑,每个客户端的文件传输都会用和服务端单独协商的密钥加密,不会出现明文传输问题。
内容的提问来源于stack exchange,提问作者배문성
相关产品推荐
相关产品推荐

