这是导致此错误的代码。
发送线程:
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 位长……任何都可以,但你必须做点什么.
