Reputation: 68
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
Upvotes: 3
Views: 4393
Reputation: 77407
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)
Upvotes: 3