Pickle 数据被截断——只有从 macOS 发送时才会出现问题

Pickle data was truncated — only a problem when sending from macos

我正在尝试将数据从我的本地 machine 运行 Big Sur 11.2.3 发送到远程服务器。

server.py

import socket, pickle
import env

print("Server is listening on port %s..." % env.PORT)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((env.HOST, env.PORT))
s.listen(1)
conn, addr = s.accept()
print("Connected to %s" % str(addr))

data = []
while True:
    packet = conn.recv(1024)
    if not packet: break
    data.append(packet)
data = pickle.loads(b"".join(data))
print(data)
conn.close()

client.py

import socket, pickle
import env

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((env.HOST, env.PORT))

variable = ['a', 'b', 'c', 'd'] * (2**14)

data_string = pickle.dumps(variable)
s.send(data_string)

s.close()
print('Data sent to server')

这最初在使用 variable = ['a', 'b', 'c', 'd'] 时有效,为了模拟发送更大的对象,我只是将它乘以大数。我最初认为如果数据大于我指定服务器作为每个数据包接收的字节数就会失败,但是这段代码一直有效直到我乘以 2**14(使用 2**13 有效)。

奇怪的是,如果我从我的 Raspberry Pi 尝试这个(即将数据从 pi 发送到远程服务器),它工作正常。但是当我在我的 mac 书中做同样的事情时,我得到

Traceback (most recent call last):
  File "server.py", line 17, in <module>
    data = pickle.loads(b"".join(data))
_pickle.UnpicklingError: pickle data was truncated

在 macOS 上无法正常工作的原因可能是什么? 如果我在本地尝试此操作(即 运行 我的 mac 书中的服务器和客户端实例),它工作正常,但当我尝试从 mac 发送到另一个 machine(当我尝试从 mac 发送到 pi 时它也失败了)。

我读到当 mac 发送和接收腌制数据的 运行 个不同版本的 python 时可能会出现问题,但我不相信成为这里的问题。远程服务器是运行python3.6.9,我的pi是运行python3.7.3。为了确保,我 运行 我的 mac 书中的脚本在虚拟环境 运行 3.6.9 中,但它仍然失败。

s.send(data_string)

您很幸运,它 在 MacOS 上失败。 send 不保证发送所有数据,但您应该检查实际发送了多少并再次(可能再次)调用 send 发送其余数据。或者使用 sendall.

来自the documentation

Returns the number of bytes sent. Applications are responsible for checking that all data has been sent; if only some of the data was transmitted, the application needs to attempt delivery of the remaining data.

为什么 send 在不同的平台或环境中表现不同?因为 send 只是将数据放入套接字发送缓冲区。缓冲区的大小有限,可以特定于 OS、OS 配置、应用程序、系统的当前状态(即内存压力与否)...。单个 send 只会将与当前空闲 space 一样多的数据放入发送缓冲区。如果缓冲区已满,它将阻塞直到一些 space 被释放。但它不会确保所有内容都可以放入套接字缓冲区。