FlatBuffers/Protobuf 中是否有支持任意 24 位带符号整数定义的可移植二进制序列化模式?
Is there a portable Binary-serialisation schema in FlatBuffers/Protobuf that supports arbitrary 24bit signed integer definitions?
我们正在以高数据速率通过 UART 串行发送数据,因此数据大小很重要。对于我们的数据,最优化的格式是 Int24,它可以简化为 C/C++ 下的 C 位域结构(GCC 编译器)以达到完美优化:
#pragma pack(push, 1)
struct Int24
{
int32_t value : 24;
};
#pragma pack(pop)
typedef std::array<Int24,32> ArrayOfInt24;
此数据与其他数据打包在一起,并在设备和云基础设施之间共享。基本上我们需要在不同架构和编程语言的设备之间发送二进制序列化。我们希望使用基于模式的二进制序列化,例如 ProtoBuffers 或 FlatBuffers,以避免客户端代码需要处理相应的二进制补码符号位处理的位移和恢复。即在非 C 语言中读取 24 位值需要以下内容:
bool isSigned = (_b2 & (byte)0x80) != 0; // Sign extend negative quantities
int32_t value = _b0 | (_b1 << 8) | (_b2 << 16) | (isSigned ? 0xFF : 0x00) << 24;
如果不存在,可以轻松修改现有的(如果有)二进制序列化库以扩展对此的支持,因为我们愿意在这方面添加到任何开源项目。
协议缓冲区使用称为 varint 的动态大小的整数编码,因此您可以只使用 uint32
或 sint32
,所有值的编码值将为四个字节或更少对于小于 2^21 的任何值,三个字节或更少(编码整数的实际大小为⌈HB/7⌉,其中 HB 是值中设置的最高位)。
确保不要使用 int32
,因为它使用了非常低效的 fixed size encoding (10 bytes!) for negative values. For repeated values, just mark them as repeated, so multiple values will be sent efficiently packed。
syntax = "proto3";
message Test {
repeated sint32 data = 1;
}
FlatBuffers 不支持 24 位整数。表示它的唯一方法是:
struct Int24 { a:ubyte; b:ubyte; c:ubyte; }
这显然不会为您进行位移,但仍允许您将多个 Int24
有效地打包到父向量或结构中。当存储在 table 中时,它也会节省一个字节,尽管在那里你可能只使用 32 位 int 会更好,因为开销更高。
protobuf 的 varint 格式的一个特别有效的用途是将其用作一种压缩方案,方法是在值之间写入增量。
在您的情况下,如果连续值之间存在任何相关性,您可以有一个 repeated sint32 values
字段。然后作为数组中的第一个条目,写入第一个值。对于所有其他条目,写下与先前值的差异。
这样[100001, 100050, 100023, 95000]
将被编码为 [100001, 49, -27, -5023]
。作为打包的 varint 数组,增量将占用 3、1、1 和 2 个字节,总共 7 个字节。与占用 12 个字节的固定 24 位编码或占用 12 个字节的非 delta varint 相比。
当然这也需要接收端的一些代码来处理。但是将先前的值相加很容易用任何语言实现。
根据各种情况,您可能希望查看 ASN.1 和未对齐的打包编码规则 (uPER)。这是一种广泛用于电话的二进制序列化,可以轻松地减少传输的位数。工具可用于 C、C++、C#、Java、Python(我认为它们涵盖了 uPER)。一个好的起点是 Useful Old Technologies。
您可能选择使用它的原因之一是 uPER 最终可能比其他任何东西都做得更好。其他好处是约束(关于值和数组大小)。您可以在您的模式中表达这些,生成的代码将根据它们检查数据。这是可以对项目产生真正影响的东西 - 传入数据的自动清理是抵御攻击的好方法 - 而这是 GPB 不做的事情。
不使用它的原因是最好的工具是商业的,而且相当昂贵。尽管有一些开源工具非常好,但不一定实现整个 ASN.1 标准(范围很广)。它也是一个学习曲线,尽管(在基本层面上)与 Google Protocol Buffers 没有太大区别。事实上,在 Google 宣布 GPB 的会议上,有人问 "why not use ASN.1?"。 Google bod 没有听说过它;有点讽刺的是,一家搜索公司并没有在网络上搜索二进制序列化技术,而是直接发明了自己的...
我们正在以高数据速率通过 UART 串行发送数据,因此数据大小很重要。对于我们的数据,最优化的格式是 Int24,它可以简化为 C/C++ 下的 C 位域结构(GCC 编译器)以达到完美优化:
#pragma pack(push, 1)
struct Int24
{
int32_t value : 24;
};
#pragma pack(pop)
typedef std::array<Int24,32> ArrayOfInt24;
此数据与其他数据打包在一起,并在设备和云基础设施之间共享。基本上我们需要在不同架构和编程语言的设备之间发送二进制序列化。我们希望使用基于模式的二进制序列化,例如 ProtoBuffers 或 FlatBuffers,以避免客户端代码需要处理相应的二进制补码符号位处理的位移和恢复。即在非 C 语言中读取 24 位值需要以下内容:
bool isSigned = (_b2 & (byte)0x80) != 0; // Sign extend negative quantities
int32_t value = _b0 | (_b1 << 8) | (_b2 << 16) | (isSigned ? 0xFF : 0x00) << 24;
如果不存在,可以轻松修改现有的(如果有)二进制序列化库以扩展对此的支持,因为我们愿意在这方面添加到任何开源项目。
协议缓冲区使用称为 varint 的动态大小的整数编码,因此您可以只使用 uint32
或 sint32
,所有值的编码值将为四个字节或更少对于小于 2^21 的任何值,三个字节或更少(编码整数的实际大小为⌈HB/7⌉,其中 HB 是值中设置的最高位)。
确保不要使用 int32
,因为它使用了非常低效的 fixed size encoding (10 bytes!) for negative values. For repeated values, just mark them as repeated, so multiple values will be sent efficiently packed。
syntax = "proto3";
message Test {
repeated sint32 data = 1;
}
FlatBuffers 不支持 24 位整数。表示它的唯一方法是:
struct Int24 { a:ubyte; b:ubyte; c:ubyte; }
这显然不会为您进行位移,但仍允许您将多个 Int24
有效地打包到父向量或结构中。当存储在 table 中时,它也会节省一个字节,尽管在那里你可能只使用 32 位 int 会更好,因为开销更高。
protobuf 的 varint 格式的一个特别有效的用途是将其用作一种压缩方案,方法是在值之间写入增量。
在您的情况下,如果连续值之间存在任何相关性,您可以有一个 repeated sint32 values
字段。然后作为数组中的第一个条目,写入第一个值。对于所有其他条目,写下与先前值的差异。
这样[100001, 100050, 100023, 95000]
将被编码为 [100001, 49, -27, -5023]
。作为打包的 varint 数组,增量将占用 3、1、1 和 2 个字节,总共 7 个字节。与占用 12 个字节的固定 24 位编码或占用 12 个字节的非 delta varint 相比。
当然这也需要接收端的一些代码来处理。但是将先前的值相加很容易用任何语言实现。
根据各种情况,您可能希望查看 ASN.1 和未对齐的打包编码规则 (uPER)。这是一种广泛用于电话的二进制序列化,可以轻松地减少传输的位数。工具可用于 C、C++、C#、Java、Python(我认为它们涵盖了 uPER)。一个好的起点是 Useful Old Technologies。
您可能选择使用它的原因之一是 uPER 最终可能比其他任何东西都做得更好。其他好处是约束(关于值和数组大小)。您可以在您的模式中表达这些,生成的代码将根据它们检查数据。这是可以对项目产生真正影响的东西 - 传入数据的自动清理是抵御攻击的好方法 - 而这是 GPB 不做的事情。
不使用它的原因是最好的工具是商业的,而且相当昂贵。尽管有一些开源工具非常好,但不一定实现整个 ASN.1 标准(范围很广)。它也是一个学习曲线,尽管(在基本层面上)与 Google Protocol Buffers 没有太大区别。事实上,在 Google 宣布 GPB 的会议上,有人问 "why not use ASN.1?"。 Google bod 没有听说过它;有点讽刺的是,一家搜索公司并没有在网络上搜索二进制序列化技术,而是直接发明了自己的...