Python Socket通信异常:客户端传图后双方控制台冻结
解决Socket传输图片后双向冻结的问题
问题原因
你的代码出现冻结是因为TCP流协议的特性导致双向阻塞:
- 服务端的
while data:循环中,client.recv(4096)会一直阻塞等待数据——TCP流没有明确的"结束标记",服务端不知道图片已经传输完毕,只有当客户端关闭socket的写通道时,recv才会返回空字节串,循环才能退出。 - 客户端发送完图片后直接调用
client.recv()等待服务端响应,但此时服务端还卡在recv循环里,两边互相等待,形成死锁。
解决方案1:关闭客户端写通道(简单直接)
客户端发送完图片后,调用shutdown(socket.SHUT_WR)关闭写端,明确告诉服务端数据已发送完成,服务端就能退出recv循环,继续执行发送响应的逻辑。
修正后的客户端代码:
import socket client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) client.connect(("127.0.0.1", 5005)) file = open("tstop/abdul.jpg", mode="rb") data = file.read(4096) print("up") while data: client.send(data) data = file.read(4096) file.close() print("down") # 关闭写端,通知服务端数据传输完毕 client.shutdown(socket.SHUT_WR) data = client.recv(2048) print ("Received response:" + str(data.decode('utf8'))) client.close()
服务端代码无需修改,原逻辑会在recv到空字节串时退出循环,继续执行后续发送操作。
解决方案2:预先传输文件大小(更灵活)
如果后续还需要保持socket双向通信,不想关闭写端,可以先发送文件的总大小,服务端根据大小接收指定字节数,完成后自动退出接收循环。
修正后的服务端代码:
import socket server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server.bind(("127.0.0.1", 5005)) server.listen() client, addr = server.accept() id = 4 print("w") # 先接收文件大小(确保大小能一次性接收) file_size = int(client.recv(1024).decode('utf8')) file = open("out.png", mode="wb") received_bytes = 0 while received_bytes < file_size: # 每次接收剩余未接收的字节数,避免多收 chunk = client.recv(min(4096, file_size - received_bytes)) if not chunk: break file.write(chunk) received_bytes += len(chunk) file.close() print("ww") client.sendall(str(id).encode('utf8')) server.close()
修正后的客户端代码:
import socket import os client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) client.connect(("127.0.0.1", 5005)) file_path = "tstop/abdul.jpg" # 获取文件大小 file_size = os.path.getsize(file_path) # 发送文件大小给服务端 client.send(str(file_size).encode('utf8')) file = open(file_path, mode="rb") data = file.read(4096) print("up") while data: client.send(data) data = file.read(4096) file.close() print("down") data = client.recv(2048) print ("Received response:" + str(data.decode('utf8'))) client.close()
方案对比
- 方案1:实现简单,适合一次性传输后仅接收响应的场景,但关闭写端后客户端无法再向服务端发送数据。
- 方案2:更灵活,支持后续双向通信,通过预先约定的文件大小明确传输结束点,避免不必要的阻塞。
内容的提问来源于stack exchange,提问作者Jordan
相关产品推荐
相关产品推荐

