我有一个简单的协议,包括4个字段:
Field-1 (4-bits)
Field-2 (6-bits)
Field-3 (4-bits)
Field-4 (2-bits)目前,我将它们组织为字节对齐方式:
Field-1,Field-3,Field-2,Field-4总之,该消息占用2个字节,开销为0字节。
为了使它向后兼容,因此我可以理解来自上一个版本的消息,我在开头添加了一个1字节版本字段,它变成:
Version-Field,Field-1,Field-3,Field-2,Field-4总共3字节,开销为1字节。
如何添加前向兼容性,以便在新版本的协议中添加新字段,同时确保旧版本的软件仍然能够理解消息,并且开销尽可能低?
发布于 2017-12-10 19:02:54
通常,您的协议将指定每条消息具有:
然后,协议的每一个新版本都允许您向符合协议前一版本的前缀中添加新数据,协议的每个版本都必须指定如何识别它定义的数据的末尾(在您的示例中,该数据的长度固定,因此很容易),以及在未来版本中定义的数据的开始。
要处理消息,使用者检查以确保它是一个足够高的版本,处理它所理解的前缀,并使用length字段跳过其余的。
对于像您的协议那样的空间限制,我可能会这样做:
发布于 2017-12-07 22:21:00
通过确保严格遵守此规则,您将拥有FC:
新版本必须使以前的版本知道字段布局。
如果您能够遵循规则,您将自动拥有BC和FC。因此,使用该规则,您只能通过将新字段附加到现有布局中来添加它们。
让我举个例子来解释。假设您需要为版本2添加这些字段:
Field-5 (1-bit)
Field-6 (7-bits)记住,新字段只能附加到现有布局中。因此,这是version 2消息布局:
Version-Field,Field-1,Field-3,Field-2,Field-4,Field-5,Field-6因为版本1已知的布局是完整的,所以版本1代码可以读取任何版本的消息(伪代码):
function readMessageVersion1(byte[] input) {
var msg = {};
msg.version = input[0];
msg.field1 = input[1] & 0x0f;
msg.field3 = input[1] >> 4 & 0x0f;
msg.field2 = input[2] & 0x3f;
msg.field4 = input[2] >> 6 & 0x03;
return msg;
}Version 1不需要检查version字段,因为已知的布局是无条件的。但是,version 2和所有其他版本都需要检查version字段。假设我们使用值2来指示版本2,这就可以了(伪代码):
function readMessageVersion2(byte[] input) {
var msg = readMessageVersion1(input);
//check version field
if (msg.version < 2) return msg;
msg.field5 = input[3] & 0x01;
msg.field6 = input[3] >> 1 & 0x7f;
return msg;
}代码最重要的部分是它重用了以前版本的代码和这个检查:
if (msg.version < 2) return msg;代码的第3版可以简单地跟随版本2,如下所示:
function readMessageVersion3(byte[] input) {
var msg = readMessageVersion2(input);
//check version field
if (msg.version < 3) return msg;
// read the input bytes here
return msg;
}将其视为未来版本的模板。通过遵循规则和示例,任何版本的协议都可以读取来自任何版本的消息,仅需1字节开销。
https://stackoverflow.com/questions/47455284
复制相似问题