2013-05-01 150 views
1

以下是導致此錯誤的代碼。EOF Python中酸洗錯誤

發送線程:

data = pickle.dumps (object); 

接收線程:

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

顯示的錯誤是

self.object = pickle.loads(data) 
EOFError 

另外添加到細節,此錯誤時只有50%的時間的。另外50%的時間,沒有錯誤!

+0

你確定你收到接收線程上的pickle的所有字節嗎? – 2013-05-01 16:46:53

+0

@Martijin Pieters你是否建議,我應該在酸洗之前進行一次睡眠呼叫,讓所有字節都有足夠的時間到達? – 2013-05-01 16:48:14

+0

我建議你在把它交給'pickle.loads'函數之前確保所有數據都已經到達。 – 2013-05-01 16:50:12

回答

5

鑑於評論,我猜測最可能的問題是,但至少有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)套接字是一個:一個字節序列,而不是一系列消息。任何你想要的結構,你必須建立數據。

這意味着你必須設計和實現一個協議 - 一種知道每個消息何時完成的方式。最簡單的協議可能是行(顯然只有在消息永遠不會有非轉義的換行符時纔有用),但是任何能夠讓你明確地查看某些數據並且說「這是消息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位數字長... 什麼作品,但你必須做東西