我正在嘗試編寫一個應用程序,它使用Google協議緩衝區通過TCP連接反序列化數據(從另一個使用協議緩衝區的應用程序發送)。問題在於,它看起來好像Python中的協議緩衝區只能反序列化字符串中的數據。由於TCP沒有明確定義的消息邊界,並且我嘗試接收的消息中有一個消息具有重複的字段,所以在最終傳遞要反序列化的字符串之前,我不知道要嘗試接收多少數據。如何使用Python和Google協議緩衝區來反序列化通過TCP發送的數據
在Python中這樣做有什麼好的做法嗎?
我正在嘗試編寫一個應用程序,它使用Google協議緩衝區通過TCP連接反序列化數據(從另一個使用協議緩衝區的應用程序發送)。問題在於,它看起來好像Python中的協議緩衝區只能反序列化字符串中的數據。由於TCP沒有明確定義的消息邊界,並且我嘗試接收的消息中有一個消息具有重複的字段,所以在最終傳遞要反序列化的字符串之前,我不知道要嘗試接收多少數據。如何使用Python和Google協議緩衝區來反序列化通過TCP發送的數據
在Python中這樣做有什麼好的做法嗎?
不要只將序列化的數據寫入套接字。首先發送包含序列化對象長度的固定大小字段。
發送側大致是:
socket.write(struct.pack("H", len(data)) #send a two-byte size field
socket.write(data)
而且recv'ing一側變成類似:
dataToRead = struct.unpack("H", socket.read(2))[0]
data = socket.read(dataToRead)
這是socket編程一個常用的設計模式。大多數設計延長了過度的線結構,包括類型字段一樣,所以你的接收端變得像:
type = socket.read(1) # get the type of msg
dataToRead = struct.unpack("H", socket.read(2))[0] # get the len of the msg
data = socket.read(dataToRead) # read the msg
if TYPE_FOO == type:
handleFoo(data)
elif TYPE_BAR == type:
handleBar(data)
else:
raise UnknownTypeException(type)
你,看起來像一個以上的非線消息格式結束:
struct {
unsigned char type;
unsigned short length;
void *data;
}
這對於未來防線的協議來說是合理的,可以防範未預見到的需求。這是一個Type-Length-Value協議,你會一次又一次地在網絡協議中找到它。
爲了擴大J.J.(完全正確)的答案,protobuf庫有沒有辦法來計算消息的長度,或者計算出發送什麼類型的protobuf對象*。因此,向您發送數據的其他應用程序必須已經做了這樣的事情。
當我不得不這樣做,我實現了一個查找表:
messageLookup={0:foobar_pb2.MessageFoo,1:foobar_pb2.MessageBar,2:foobar_pb2.MessageBaz}
...並基本上就是J·J·做沒有,但我也有一個幫手功能:
def parseMessage(self,msgType,stringMessage):
msgClass=messageLookup[msgType]
message=msgClass()
message.ParseFromString(stringMessage)
return message
...我打電話把字符串變成一個protobuf對象。
(*),我認爲這是可能通過封裝特定消息的容器消息
這兩個答案都很好,但沒有封裝的炸爐匠(根據我)是前進的道路。 – 2013-10-15 14:46:37
內另一個方面考慮(雖然對於簡單的情況下),以避開這是你使用單條信息的單個TCP連接。在這種情況下,只要您知道預期的消息是什麼(或使用Union Types來確定運行時的消息類型),則可以將TCP連接打開爲「開始」分隔符,並將連接關閉事件作爲最後的分隔符。這樣做的好處是您可以快速收到整個郵件(而在其他情況下,TCP流可以暫時保留一段時間,延遲收到您的整個郵件)。如果你這樣做,你不需要任何明確的帶內成幀,因爲TCP連接的生命週期本身就是一個幀。
+1令人難以置信的詳細和真棒的答案。謝謝!! – jathanism 2010-01-11 15:30:50
使用struct.pack(「H」,len(data))會產生一個重要結果:數據長度必須小於65536字節。你可以通過使用一個無符號long long而不是'Q'(最大大小= 18000 PB)來增加允許的最大數據大小。 – Flimm 2013-02-06 16:59:48