Receive delimited Protobuf message in python via TCP

╄→尐↘猪︶ㄣ 提交于 2020-02-23 05:00:33

问题


I am trying to receive a protobuf message, which was send from a java application with "writeDelmitedTo()" inside my python application.

After some research I already came across this code to read the message from the socket, decode it and parse it.

data = sock.recv()
(size, position) = decoder._DecodeVarint(data, 0)
msg = MessageWrapper_pb2.WrapperMessage().ParseFromString(data[position:position + size])

What I am getting now is a google.protobuf.message.DecodeError: Truncated message Exception.

Has anyone encountered a similar problem or knows how to read delimited data from a socket and parse it correctly?

Edit:

This is the solution that worked for me.

def read_java_varint_delimited_stream(sock):
    buf = []
    data = sock.recv()
    rCount = len(data)
    (size, position) = decoder._DecodeVarint(data, 0)

    buf.append(data)
    while rCount < size+position:
        data = sock.recv(size+position-rCount)
        rCount += len(data)
        buf.append(data)

    return b''.join(buf), size, position

def readMessage(sock):
    data, size, position = read_java_varint_delimited_stream(sock)
    msg = MessageWrapper_pb2.WrapperMessage()
    msg.ParseFromString(data[position:position + size])

    return msg

回答1:


TCP is a stream protocol and there is nothing that says a recv on one end is paired with a single send on the other end. Message based protocols need some way to mark their boundaries so the receiver knows how to find message boundaries.

The writeDelimitedTo docs say that a varint size is sent and then the data. So, read the varint and then read that number of bytes.

Digging deeper, the varint docs describe how its value is encoded by using a byte's high-bit to mark continuation. We we can write up our own decoder

import struct

def read_java_varint_delimited_stream(sock):
    sz = 0
    while True:
        vbyte, = struct.unpack('b', sock.recv(1))
        sz = (vbyte << 7) + (vbyte & 0x7f)
        if not vbyte & 0x80:
            break
    data = []
    while sz:
        buf = sock.recv(sz)
        if not buf:
            raise ValueError("Buffer receive truncated")
        data.append(buf)
        sz -= len(buf)
    return b''.join(buf)


来源:https://stackoverflow.com/questions/43897955/receive-delimited-protobuf-message-in-python-via-tcp

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!