Skip to main content
 首页 » 编程设计

python之在 python 中 pickle 时出现 EOF 错误

2025年05月04日18zhujiabin

这是导致此错误的代码。

发送线程:

 data = pickle.dumps (object); 

接收线程:

 self.object = pickle.loads(data) // Erroneous line 

显示的错误是

    self.object = pickle.loads(data) 
EOFError 

另外补充一下细节,这个错误只发生了 50%。其他 50% 的时间,没有错误!

请您参考如下方法:

鉴于评论,我猜测了最有可能的问题,但至少有 50% 的可能性我猜错了,在这种情况下……告诉我,我会删除回答。

我猜您正在尝试将流式套接字当作一系列消息来使用。这是网络编程新手中非常普遍的问题。

假设发件人做了这样的事情:

data = pickle.dumps(object); 
self.sock.sendall(data) 

接收者做这样的事情:

data = self.sock.recv(4096) 
self.object = pickle.loads(data) 

这在简单测试中可能有 99% 的时间有效,但在实际使用中却行不通。您将收到部分消息,或在一次通话中收到多条消息,或上述消息的一些有趣组合(例如消息 2 的一半、消息 3 的全部以及消息 4 的三分之一)。

因此,您将向 loads 传递一条部分消息,并返回一个错误,告诉您这不是一个完整的 pickle。

那不是因为什么东西坏了;这就是它应该的工作方式。 (TCP) 套接字是一个流:字节序列,而不是消息序列。任何你想要的结构,你都必须构建到数据中。

这意味着您必须设计并实现一个协议(protocol)——某种了解每条消息何时完成的方式。最简单的协议(protocol)可能是行(显然只有在消息永远不会有未转义的换行符时才有用)和 netstrings ,但是任何能让您以明确的方式查看某些数据并说“这是消息 0,这是消息 1,等等”的任何东西。将工作。

通常,这意味着将接收到的数据附加到某个缓冲区,并循环遍历该缓冲区中的消息。例如,用线条代替这个:

while True: 
    line = sock.recv(4096) 
    do_stuff(line) 

……你需要这个:

rdbuf = '' 
while True: 
    rdbuf += sock.recv(4096) 
    lines = rdbuf.split('\n') 
    rdbuf = lines[-1] 
    for line in lines[:-1]: 
        dostuff(line) 

仔细想想,这和文件没什么区别。想象一下这段代码:

with open('foo.data', 'wb') as f: 
    f.write('123') 
    f.write('45') 
with open('foo.data', 'rb') as f: 
    while True: 
        number = f.read() 

这将读取 '12345',而不是 '123'。如果你想得到 '123',你需要一些方法知道只能读取 3 个字节。坚持长度前缀,或添加空格作为分隔符,或者只是从外部知道第一个数字总是 3 位长……任何都可以,但你必须做点什么.