2

这是导致此错误的代码。

发送线程:

 data = pickle.dumps (object);

接收线程:

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

显示的错误是

    self.object = pickle.loads(data)
EOFError

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

4

1 回答 1

6

鉴于评论,我猜出了最可能的问题,但至少有 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 位长……任何事情都可以,但你必须做点什么

于 2013-05-01T17:46:34.873 回答