protobufjs序列化后如何拼接上消息Id

protobufjs序列化后得到的是arrayBuffer

        let pb = pbkiller.loadAll('proto', '');
        let player = new pb.UserLoginMsgReq();  
        player.openID = 0;
        player.logintype = 3;
        player.gameID = 3;
        let data = player.toArrayBuffer();

如何在data前面加上消息ID 以便服务收到数据后 进行反序列化?

let pbData = [];
pbData = pbData.concat(“id”).concat(data);

1赞

会多加一个逗号 并且截取掉消息号后 不能反序列化

你好我是pbkiller的开发者,所有potobuf数据都需要事先定义,你可以参考下面的做法

message PBMessage {
   uint32 id = 0;       //消息ID
   bytes data = 1;   //上层协议
}

...
let data = player.toArrayBuffer();
//实例化一个PBMessage消息
let message = new pb.PBMessage();
//设置消息ID和数据
message.id = xxx;
message.data = data;
//将message序列化发给服务器,服务器需要做两次反序列化
socket.send(message.toArrayBuffer());

你好 我正是使用了pbkiller 因为公司服务端要求在protobuf序列化后的数据包前面加上消息号
所以大概是要这样 socket.send(“1001”+message.toArrayBuffer());
我现在采用的办法是把序列化后得到的arrayBuffer转为字符串然后拼接上消息好再转变成arrayBuffer
大神 有没有更好的办法?

方法就是在上面给你写的, 做一个通用协议,有头部,数据部分,头部放id或其它的东西,这样方便扩展

此方法需要前后端配合,后端解码PBMessage,通过PBMessage.id将其路由给具体的处理函数解码PBMessage.data。

后端使用golang的leaf会有这样的需求, 修改proto文件会导致前后端对不上。
所以只能在arraybuffer前拼一个2字节的id

求解决办法

那是因为leaf的解消息过程就是取头来做为ID,叫服务端去改一下就好了。

使用二进制插入消息id,前几天才做的

请问怎么做到的呢?

你这样需要encode或者decode两次。。会影响效率么。。
其实楼主这样是c++等其他语言使用官方protobuf的通常做法,就是在encode之后的数据前面加上两个int,一个表示id,一个表示数据长度。

从服务器下发到客户端的过程中:
1.不知道是用哪个message的对象解析,因为是根据消息ID去找message对象的
2.消息ID已经放在message对象里面了,没有放到协议头上
如何解决这个问题?

我之前的PB协议设计有两层,头部和内容部分,你不把ID放到协议头上,就没法做到自解释

我在定义消息id时,通过提出注释,获取到id对应的请求对象和响应对象

这是生成的ID对应的请求响应映射表

下面是上层使用,不用关心请求、响应如何解码

1赞

大佬,解决了吗?有代码吗?

服务器是小端的情况下
写入数据. buf就是你要发送的携带消息号序列化数据
msg 数据内容
msgId 消息号

let buffer:Uint8Array = yourProtobufClass.encode(msg).finish();
let bufferArr = Array.from(buffer);
let buf= new Uint8Array([msgId,0,… bufferArr]).buffer;

读取数据

msg是你从服务器收到的完整数据
msgId是服务器发给你的消息号
finalMsg是最终你想要的数据内容

let uint8Array = new Uint8Array(msg);
let bufferArr = Array.from(uint8Array);

下面是从完整数据取出 msgId并留下 内容数据
msgId = bufferArr.shift();
bufferArr.shift();

解出该消息类的数据内容
let decodeMsg = yourProtobufClass.decode(bufferArr);
let finalMsg = decodeMsg.toJSON();

服务器是大端的 就不写啦。

如果不懂可以 关注我公众号 加我微信。发你模块

服务器是小端的情况下
写入数据. buf就是你要发送的携带消息号序列化数据
msg 数据内容
msgId 消息号

let buffer:Uint8Array = yourProtobufClass.encode(msg).finish();
let bufferArr = Array.from(buffer);
let buf= new Uint8Array([msgId,0,… bufferArr]).buffer;

读取数据

msg是你从服务器收到的完整数据
msgId是服务器发给你的消息号
finalMsg是最终你想要的数据内容

let uint8Array = new Uint8Array(msg);
let bufferArr = Array.from(uint8Array);

下面是从完整数据取出 msgId并留下 内容数据
msgId = bufferArr.shift();
bufferArr.shift();

解出该消息类的数据内容
let decodeMsg = yourProtobufClass.decode(bufferArr);
let finalMsg = decodeMsg.toJSON();

服务器是大端的 就不写啦。

如果不懂可以 关注我公众号 加我微信。发你模块

这个问题你后来用什么方式解决的,不想写大量的switch case,能自动找到最好



看看encode 和 decode 的实现

问题是如何优雅的把消息ID映射到protobuf 的message