You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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,提问作者배문성

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 11:24:06