这是导致此错误的代码。
发送线程:
data = pickle.dumps (object);
接收线程:
self.object = pickle.loads(data) // Erroneous line
显示的错误是
self.object = pickle.loads(data)
EOFError
另外补充一点,这个错误只有 50% 的时间发生。其他 50% 的时候,没有错误!
这是导致此错误的代码。
发送线程:
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
并返回一个错误,告诉您这不是一个完整的泡菜。
那不是因为任何东西都坏了;这就是它应该如何工作的方式。(TCP)套接字是一个流:一个字节序列,而不是一个消息序列。除此之外,您想要的任何结构都必须构建到数据中。
这意味着您必须设计和实现一个协议——以某种方式知道每条消息何时完成。最简单的协议可能是行(显然只有在消息永远不会有未转义的换行符时才有用)和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 位长……任何事情都可以,但你必须做点什么。