我有消息
message Msg
{
uint32 a;
uint32 b;
bool c;
}
当我使用pb_encode
写消息时,我注意到流的数量。bytes_written取决于有多少Msg
字段从其默认值更改。
我真的不想在char * buffer
之外再发送一个单独的stream.bytes_written
参数。
我正在考虑做这样的事情
message Msg_ser
{
required int size;
bytes Msg_ser_dat = 1 [(nanopb).max_size = 32];
}
所以pb_encode
会写入Msg_ser.Msg_ser_dat
,然后message Msg_ser
本身会被序列化。
这种将缓冲区的大小存储在缓冲区本身的方法有什么错误吗?
是的,这种方法有问题。
除非最近发生了一些变化,否则在GPB中没有消息自定义的意图。如果消息要在另一个(或许多)GPB消息中存储或传输,则必须有一些单独的方法来标记消息的开始/结束。
如果有人设法按照您的建议去做,并且有线格式恰好允许收件人在学习其他内容之前学习大小字段,那很好。但是不能保证有线格式总是启用这个功能。
发送单独的bytes_written
值是一种方法,即发送的前4个字节将被解析为本机整数,指示GPB编码消息中有多少个后续字节。大量使用GPB的OpenStreetMap在其数据文件中有一个小协议,说明下一个GPB消息的长度和它是什么类型的消息,这允许读者轻松跳过。
这个想法的另一个问题是,它假设发送的每个字节都被接收。例如,RS232连接绝对不是这种情况;发送方可以愉快地发送字节流,但如果接收方没有连接、打开、运行和保持同步,这些字节就永远消失了。因此,接收方可能已经开始接收部分字节,并且不知道它接收到的第一个字节实际上不是消息的size
字段。在这种情况下,最好有某种唯一的消息开始/结束字节模式,接收方可以检测到,丢弃读字节,直到它得到该模式。
我知道这些很讨厌,但这绝对是最好的。您必须在GPB消息传递层下面有一个单独的消息划分协议(如果将其视为分层协议堆栈的话)。您根本无法明智地将一个协议层硬塞到另一个协议层中,特别是当技术(GPB)无意支持该协议层时。
另一种方法(如果你有网络或其他可靠的流连接)是使用像ZeroMQ这样的协议,它会为你处理消息划分。
其他序列化是自划分的。XML是(标签打开/关闭必须是一致的),JSON是(花括号{}),一些ASN.1线格式也是,但GPB不是。