簡體   English   中英

如何使用Python和Google的Protocol Buffers來反序列化通過TCP發送的數據

[英]How to use Python and Google's Protocol Buffers to deserialize data sent over TCP

我正在嘗試編寫一個應用程序,該應用程序使用Google的協議緩沖區通過TCP連接反序列化數據(使用協議緩沖區從另一個應用程序發送)。 問題是,看起來Python中的協議緩沖區只能從字符串反序列化數據。 由於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)

這是套接字編程的常見設計模式。 大多數設計擴展了線上結構以包括類型字段,因此您的接收方將變為:

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;
}

這樣可以有效地解決線路協議面臨無法預料的需求。 它是一種類型 - 長度 - 值協議,您可以在網絡協議中一次又一次地找到它。

為了擴展JJ的(完全正確的)答案,protobuf庫沒有辦法計算出消息本身有多長,或者計算出正在發送什么類型的protobuf對象*。 因此,向您發送數據的其他應用程序必須已經在執行此類操作。

當我不得不這樣做時,我實現了一個查找表:

messageLookup={0:foobar_pb2.MessageFoo,1:foobar_pb2.MessageBar,2:foobar_pb2.MessageBaz}

...並且基本上做了JJ所做的事,但我也有一個輔助函數:

    def parseMessage(self,msgType,stringMessage):
        msgClass=messageLookup[msgType]
        message=msgClass()
        message.ParseFromString(stringMessage)
        return message

...我打電話將字符串轉換為protobuf對象。

(*)我認為可以通過在容器消息中封裝特定消息來解決這個問題

要考慮的另一個方面(盡管是更簡單的情況)是您為單個消息使用單個TCP連接。 在這種情況下,只要您知道預期的消息是什么(或使用聯合類型在運行時確定消息類型),您可以使用TCP連接打開作為“開始”分隔符,並將連接關閉事件用作最后的分隔符。 這樣做的好處是,您可以快速接收整個消息(而在其他情況下,TCP流可以保留一段時間,從而延遲收到整個消息)。 如果這樣做,則不需要任何明確的帶內成幀,因為TCP連接的生命周期充當幀本身。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM