python client 与 java netty server , 用protobuf通讯的问题

此时如果客户端也是netty,那么通讯没有问题,但如果是非java语言,那么如果直接发送/接受protobuf序列化后的二进制包,会报以下异常:
io.netty.handler.codec.DecoderException: com.google.protobuf.InvalidProtocolBufferException: Protocol message contained an invalid tag (zero).
服务端采用了:
pipeline.addLast(“frameDecoder”, new ProtobufVarint32FrameDecoder());
pipeline.addLast(“frameEncoder”,
new ProtobufVarint32LengthFieldPrepender());
在对每个protobuf消息进行发送前,会加一个消息的长度,同时解码的时候,也需要先解析这个长度再解析消息,以免出现半包、粘包问题。
以python为例
//把protobuf对象传过来

	def sendSig(self,sig):
	       //把protobuf数据反序列化
	        print("=>", sig.SerializeToString())
	        value = len(sig.SerializeToString())
	        bits = value & 0x7f
	        value >>= 7
	        while value:
	            self.send_queue.put(six.int2byte(0x80 | bits))
	            bits = value & 0x7f
	            value >>= 7
	        self.send_queue.put(six.int2byte(bits))
	        self.send_queue.put(sig.SerializeToString())

详解 self.send_queue.put 这个可以理解是个队列,首先要定义一个队列把数据存入进去! 具体编码细节可以搜索Varint32!在socket发送时候 取得时候会有一个bug!有时候回去三次或两次,在发送时候请判断好
至于接受消息,凑合着用吧

class FFRespReciver(Thread):

PARSING_LEN = 0
PARSING_MSG = 1

def __init__(self,ffconnector):
    super(FFRespReciver,self).__init__()
    self.ffconnector = ffconnector
    self.data_buffer = b""
    self.parse_status = FFRespReciver.PARSING_LEN
    self.msg_len = 0

def run(self):
    while True:
        data = self.ffconnector.recv_queue.get()
        for b in data:
            if self.parse_status == FFRespReciver.PARSING_LEN:
                self.data_buffer += six.int2byte(b)
                if not (b & 0x80):
                    self.msg_len = DecodeVarint(self.data_buffer)
                    self.parse_status = FFRespReciver.PARSING_MSG
                    self.data_buffer = b""
                    continue
            elif self.parse_status == FFRespReciver.PARSING_MSG:
                self.data_buffer += six.int2byte(b)
                if len(self.data_buffer) == self.msg_len:
                    sig = SIG.Sig()
                    sig.ParseFromString(self.data_buffer)
                    self.process(sig)
                    self.data_buffer = b""
                    self.msg_len = 0
                    self.parse_status = FFRespReciver.PARSING_LEN

def process(self,sig):
    print(sig)
    //do the dirty job
def DecodeVarint(buffer):
    mask = (1 << 32) - 1
    result_type = int
    result = 0
    shift = 0
    for b in buffer:
        result |= ((b & 0x7f) << shift)
        shift += 7
        if shift >= 64:
            raise Exception('Too many bytes when decoding varint.')
    result &= mask
    result = result_type(result)
    return result

即用个状态机,先接受消息长度,解析后,接受消息并处理,然后继续接受消息长度。

猜你喜欢

转载自blog.csdn.net/qq_39150073/article/details/85778198