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

Python Socket+Pickle流式传输大Numpy数组时挂起问题求助

问题分析与修复

你的代码出现挂起是因为两个关键问题:端口不匹配,以及客户端接收逻辑未明确单次传输的边界,导致双方死锁。

核心问题拆解

  1. 端口不匹配:服务器绑定的端口是12345,但客户端连接的是12347,这会导致客户端无法正常连接服务器,后续逻辑直接异常。
  2. 接收逻辑死锁:客户端内层的while True循环会一直调用recv,直到返回空字节(即socket被关闭),但服务器是在循环中持续发送数据,不会关闭连接。第一次传输完成后,服务器等待客户端的ACK,而客户端却卡在recv里等待下一个数据块(此时服务器没发数据,因为在等ACK),双方互相等待,导致程序挂起。

修复后的代码

服务器端

import socket
import numpy as np
import pickle
import struct
import time

s = socket.socket()
print("Socket successfully created")

port = 12345
s.bind(('', port))
print("socket binded to %s" % (port))

s.listen(5)
print("socket is listening")

c, addr = s.accept()
print('Got connection from', addr)

try:
    while True:
        x = np.random.random([100, 100, 2])
        data = pickle.dumps(x, protocol=5)
        # 先发送数据长度(用struct打包成4字节无符号整数)
        c.sendall(struct.pack('!I', len(data)))
        # 发送实际的pickle数据
        c.sendall(data)
        
        # 等待客户端ACK
        ack = c.recv(1024)
        if not ack:
            break

except ConnectionResetError:
    print('Connection reset by peer')
    time.sleep(5)
finally:
    c.close()
    s.close()

客户端

import socket
import numpy as np
import pickle
import struct
import time

s = socket.socket()

port = 12345  # 修正为和服务器一致的端口
try:
    s.connect(('127.0.0.1', port))

    while True:
        # 先接收数据长度(4字节)
        len_data = s.recv(4)
        if not len_data:
            break
        data_len = struct.unpack('!I', len_data)[0]
        
        # 接收指定长度的数据
        data = b""
        while len(data) < data_len:
            chunk = s.recv(min(1024, data_len - len(data)))
            if not chunk:
                break
            data += chunk
        
        # 解析numpy数组并打印字节数
        arr = pickle.loads(data)
        print(arr.nbytes)
        
        # 发送ACK给服务器
        s.sendall(b'ACK')

except ConnectionResetError:
    print('Connection reset by peer')
    time.sleep(5)
finally:
    s.close()

修复说明

  • 端口统一:确保客户端和服务器使用相同端口,建立有效连接。
  • 明确传输边界:通过先发送数据长度,让客户端知道每次需要接收多少字节,避免无限等待。struct.pack和struct.unpack用于将整数转换为固定长度字节流,保证跨平台兼容性。
  • 避免死锁:服务器发送完数据后等待ACK,客户端接收完数据后立即发送ACK,形成可靠的请求-响应循环,不会出现互相等待的情况。

内容的提问来源于stack exchange,提问作者user_404

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 17:05:21