仅含默认枚举字段的Protobuf Response序列化长度为0的解决办法
解决Protobuf仅序列化默认值OK时无数据的问题
在proto3规范中,字段默认值(如枚举OK=0)不会被序列化,这就导致仅设置status=OK的Response消息编码后长度为0,无法正常发送。在无法修改Protobuf定义的情况下,可以通过手动补充默认字段的编码来解决这个问题。
修改后的Rust代码如下:
pub fn generate_response(data: Result<RequestResponse, String>) -> BytesMut { let mut response = Response::default(); match data { Ok(request_response) => { match request_response.request { Msg::Reset(_) => { response.set_status(Status::Ok); }, Msg::OneToAll(_) => { response.set_status(Status::Ok); response.shortest_path_length = request_response.length; } Msg::OneToOne(_) => { response.set_status(Status::Ok); response.total_length = request_response.length; } Msg::Walk(_) => { response.set_status(Status::Ok); }, } } Err(msg) => { response.set_status(Status::Error); response.err_msg = msg.parse().unwrap(); } } let mut buf = Vec::new(); response.encode(&mut buf).unwrap(); // 当编码后为空时,手动写入status=OK的Protobuf编码 if buf.is_empty() { // 字段tag=1(类型为varint,tag值为1<<3 | 0 = 8),值为0(OK的枚举值) buf.extend_from_slice(&[0x08, 0x00]); } BytesMut::from(buf) }
原理说明
- Protobuf编码规则中,
status字段的tag是1,枚举类型属于varint类型,因此tag的编码值为0x08;枚举值OK=0的varint编码为0x00。 - 当
encode后的缓冲区为空时,说明所有字段都是默认值,此时手动添加这两个字节,就能生成一个合法的包含status=OK的Protobuf消息。 - 接收端解析时,即使没有显式收到该字段,也会自动填充为默认值
OK,完全符合业务逻辑,同时解决了空消息无法发送的问题。
内容的提问来源于stack exchange,提问作者Martin kala
相关产品推荐
相关产品推荐

