通过TCP在python中接收分隔的Protobuf消息

时间:2017-05-10 16:20:37

标签: python sockets protocol-buffers

我正在尝试接收一个protobuf消息,该消息是从一个带有" writeDelmitedTo()"的Java应用程序发送的。在我的python应用程序中。

经过一番研究后,我已经遇到过这段代码,从套接字读取消息,解码并解析它。

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

我现在得到的是google.protobuf.message.DecodeError:截断的邮件异常。

是否有人遇到类似问题或知道如何从套接字读取分隔数据并正确解析它?

修改

这是对我有用的解决方案。

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 个答案:

答案 0 :(得分:1)

TCP是一种流协议,没有任何内容表示一端的recv与另一端的单send配对。基于消息的协议需要某种方式来标记它们的边界,以便接收方知道如何查找消息边界。

writeDelimitedTo docs表示发送varint大小,然后发送数据。因此,请阅读varint,然后读取该字节数。

深入挖掘,varint docs描述了如何使用字节的高位标记连续来编码其值。我们可以编写自己的解码器

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)