Python基于Socket传输文件完成后 服务端挂起无法退出接收循环
问题根因
TCP是无内置消息边界的面向字节流协议,服务端recv()只有在对端完全关闭连接、收到TCP FIN包的时候,才会返回空字节触发退出逻辑。
当前实现中,客户端把全部文件内容发送完成后,既没有告知服务端“传输已经结束”,也没有关闭自身的套接字写通道,连接一直处于“可双向收发数据”的状态,服务端自然会一直阻塞在recv()调用上,永远等不到空返回值。
最小改动修复方案
只需要在客户端发送完全部文件数据后,调用套接字的shutdown方法半关闭写通道即可——这个操作只会告知对端“我这边不会再发送任何新数据”,不会影响后续客户端接收服务端的响应,不需要直接关闭整个套接字。
修改后的客户端代码:
def download_file(self, file_name): with open(file_name, "rb") as file: while True: l = file.read(64) if not l: break self.s.sendall(l) # 所有数据发送完成,半关闭写通道,触发对端recv返回空值 self.s.shutdown(socket.SHUT_WR)
现有服务端代码的逻辑优化
当前服务端的接收逻辑存在小隐患:哪怕后续触发了空接收的退出分支,代码依然会执行一次空字节的文件写入,建议调整逻辑把写操作挪到空值判断之后:
def download_file(self, file_name): downloading = True with open(file_name, "wb") as file: while downloading: l = self.client_socket.recv(64) if not l: print("downloaded") downloading = False break file.write(l)
工程化通用方案(适合长连接复用场景)
如果后续需要在单个TCP连接上传输多个文件,不适合每次传完就关闭写通道,可以在正式传输文件内容前,先把文件的总字节数用固定长度的字节格式(比如4字节/8字节大端整数)发给服务端。服务端收到元信息后,累计接收的字节数达到文件总长度时,就可以主动终止接收流程,不需要依赖连接关闭的信号。
内容的提问来源于stack exchange,提问作者jerev7
相关产品推荐
相关产品推荐

