Как использовать Python и Буферы Протокола Google для десериализации данных, отправленных по TCP

Я пытаюсь записать приложение, которое использует буферы протокола Google для десериализации данных (отправленный от другого приложения с помощью буферов протокола) по соединению TCP. Проблема состоит в том, что выглядит, как будто буферы протокола в Python могут только десериализовать данные из строки. Так как TCP не имеет четко определенных границ сообщения и одного из сообщений, которые я пытаюсь получить, имеет повторное поле, я не буду знать сколько данных пытаться получить прежде наконец передать строку, которая будет десериализована.

Есть ли какие-либо хорошие методы для того, чтобы сделать это в Python?

17
задан Jonas 20 April 2010 в 18:13
поделиться

2 ответа

Не просто записывайте сериализованные данные в сокет. Сначала отправьте поле фиксированного размера, содержащее длину сериализованного объекта.

Отправляющая сторона приблизительно:

socket.write(struct.pack("H", len(data))    #send a two-byte size field
socket.write(data)

А возвратная сторона становится чем-то вроде:

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

Это делает разумную работу по защите проводного протокола от непредвиденных требований в будущем. Это протокол Type-Length-Value , который вы снова и снова найдете в сетевых протоколах.

36
ответ дан 30 November 2019 в 11:27
поделиться

, чтобы расширить ответ J.J. (совершенно верно), у библиотеки protobuf нет возможности выяснить, как долго сообщения находятся сами по себе, или выяснить, какой тип объекта protobuf посылается*. Так что другое приложение, которое посылает вам данные, должно уже делать что-то подобное.

Когда мне пришлось это сделать, я реализовал lookup table:

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

...которую я вызвал, чтобы превратить строку в протобуф-объект.

(*) Я думаю, что можно обойти это, инкапсулируя специфические сообщения внутри сообщения контейнера

.
4
ответ дан 30 November 2019 в 11:27
поделиться
Другие вопросы по тегам:

Похожие вопросы: