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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 18:05:09