FAST协议详解2 操作符

一、概述

操作符是FAST进行数据压缩的法宝之一,比如一个递增的数字,如果通过传统方式传输(比如二进制)则每一次都需要传递一个完整的数字,而使用递增操作符后,则不需要再传递这个字段,接收方根据模版里的操作符属性,自动将该字段的值+1即可。

 

二、操作符类型

看接口文档,存在以下类型的操作符。

操作符

说明

备注

CONSTANT

常量操作符

在模版里就定义好了该值,流中不再传输。

COPY

复制操作符

流中若前后两个消息该字段值一致,则不需要进行传输。

DEFAULT

默认操作符

消息中的字段有默认值,当字段值与默认值不同时进行传输。

DELTA

差值操作符

仅传输前后两个消息中该字段的差值。

INCREMENT

递增操作符

如果传输前后两个消息中该字段值是递增的,则不需要进行传输。

NONE

无操作符

传输前后两个消息该字段无关系,需要传输。

TAIL

接尾操作符

仅传输字符串的尾部差异值。

 

三、操作符与编码

1、CONSTANT常量操作符

 

使用上述代码输出为:

msg111= -> {123, 1, 2, 3}

outByteStr=11000000,11111011,10000001,10000011,

可以看到,模版中第二个字段的操作符被设置为CONSTANT后,在进行编码前,我们不需要对该字段进行设值,编码后的FAST流中也没有对该字段的值进行压缩,但解码后自动获得了该值:2。如果我们对具备CONSTANT操作符的字段进行赋值,会产生报错。

 

2、COPY复制操作符

 

使用上述代码输出为:

msg111= -> {123, 1, 2, 3}

msg111= -> {123, 1, 2, 3}

outByteStr=11100000,11111011,10000001,10000010,10000011,10000000,10000001,10000011,

二进制数据解析如下:

二进制数

解码过程

解码结果

11100000

 

PMap

11111011

01111011=123

123

10000001

00000001=1

1

10000010

00000010=2

2

10000011

00000011=3

3

10000000

 

PMap

10000001

00000001=1

1

10000011

00000011=3

3

可以看到,我们将第二个字段设置为COPY操作符,编码时前后两条数据该字段值都是2,则在FAST流中直接省略了该字段的传输。

 

问题:如果传输不一样的值会如何

 

使用上述代码输出为:

msg111= -> {123, 1, 2, 3}

msg111= -> {123, 1, 22, 3}

outByteStr=11100000,11111011,10000001,10000010,10000011,10100000,10000001,10010110,10000011,

二进制数解析如下:

二进制数

解码过程

解码结果

11100000

 

PMap

11111011

01111011=123

123

10000001

00000001=1

1

10000010

00000010=2

2

10000011

00000011=3

3

10100000

 

PMap

10000001

00000001=1

1

10010110

00010110=22

22

10000011

00000011=3

3

 

可以看到,当前后两条数据传输的值不一样时,FAST流中会传递该字段的最新值。

 

问题:如果传输不一样的值后,再次传输一样的值,是以第一次传输的数据为准,还是以上一次传输的数据为准。

答:始终是以上一个数据为准。举例来说:

//第一段数据

Message message1 = new Message(template);

message1.setInteger(1, 1);

message1.setInteger(2, 2);

message1.setInteger(3, 3);

//第二段数据

Message message2 = new Message(template);

message2.setInteger(1, 1);

message2.setInteger(2, 22);

message2.setInteger(3, 3);

//第三段数据

Message message3 = new Message(template);

message3.setInteger(1, 1);

message3.setInteger(2, 22);

message3.setInteger(3, 3);

上述代码,第三段数据的第二个字段值与第二段数据一致,则FAST编码时第二个字段不再传输。修改下:

//第三段数据

Message message3 = new Message(template);

message3.setInteger(1, 1);

message3.setInteger(2, 2);

message3.setInteger(3, 3);

上述代码,第三段数据的第二个字段值与第一段数据一致,但与第二段不一致则FAST编码时还是会传输该字段值。

 

3、DEFAULT默认操作符

 

使用上述代码输出为:

msg111= -> {123, 1, 2, 3}

outByteStr=11000000,11111011,10000001,10000011,

可以看到,当传输值与DEFAULT值一致时,FAST流中将不传输该字段。我们略做修改如下:

Message message = new Message(template);

message.setInteger(1, 1);

message.setInteger(2, 22);

message.setInteger(3, 3);

则输出变为:

msg111= -> {123, 1, 22, 3}

outByteStr=11100000,11111011,10000001,10010110,10000011,

可以看到,当传输值与DEFAULT值不一致时,FAST流中会传输该字段。

 

4、DELTA差值操作符

 

使用上述代码输出为:

msg111= -> {123, 1, 2, 3}

msg111= -> {123, 1, 22, 3}

msg111= -> {123, 1, 222, 3}

outByteStr=11000000,11111011,10000001,10000010,10000011,10000000,10000001,10010100,10000011,10000000,10000001,00000001,11001000,10000011,

二进制数解析如下:

二进制数

解码过程

解码结果

11000000

 

PMap

11111011

01111011=123

123

10000001

00000001=1

1

10000010

00000010=2

2

10000011

00000011=3

3

10000000

 

PMap

10000001

00000001=1

1

10010100

00010100=20

22

10000011

00000011=3

3

10000000

 

PMap

10000001

00000001=1

1

00000001,11001000

00000001=1

01001000=72

128+72=200

222

10000011

00000011=3

3

可以看到,使用DELTA差值操作符后,只需要传输前后两个数据的差值即可。

 

问题:如果是减小而不是增大会怎样?我们做如下修改:

//第一段数据

Message message1 = new Message(template);

message1.setInteger(1, 1);

message1.setInteger(2, 2);

message1.setInteger(3, 3);

//第一段数据编码

byte[] outByte1 = encoder.encode(message1);

//第二段数据

Message message2 = new Message(template);

message2.setInteger(1, 1);

message2.setInteger(2, 22);

message2.setInteger(3, 3);

//第二段数据编码

byte[] outByte2 = encoder.encode(message2);

//第三段数据

Message message3 = new Message(template);

message3.setInteger(1, 1);

message3.setInteger(2, 2);

message3.setInteger(3, 3);

//第三段数据编码

byte[] outByte3 = encoder.encode(message3);

 

使用上述代码输出为:

msg111= -> {123, 1, 2, 3}

msg111= -> {123, 1, 22, 3}

msg111= -> {123, 1, 2, 3}

outByteStr=11000000,11111011,10000001,10000010,10000011,10000000,10000001,10010100,10000011,10000000,10000001,11101100,10000011,

二进制数解析如下:

二进制数

解码过程

解码结果

11000000

 

PMap

11111011

01111011=123

123

10000001

00000001=1

1

10000010

00000010=2

2

10000011

00000011=3

3

10000000

 

PMap

10000001

00000001=1

1

10010100

00010100=20

22

10000011

00000011=3

3

10000000

 

PMap

10000001

00000001=1

1

11101100

1101100= -20

2

10000011

00000011=3

3

 

可见,对于减小的情况,只需要传递负值即可。

 

问题:浮点数也可以这样减小或增大吗?

 

使用上述代码输出为:

msg111= -> {123, 1, 2.2, 3}

msg111= -> {123, 1, 22.22, 3}

msg111= -> {123, 1, 11.11, 3}

outByteStr=11000000,11111011,10000001,11111111,10010110,10000011,10000000,10000001,11111111,00010001,10011000,10000011,10000000,10000001,10000000,01110111,10101001,10000011,

二进制数解析如下:

二进制数

解码过程

解码结果

11000000

 

PMap

11111011

01111011=123

123

10000001

00000001=1

1

11111111

1111111= -1

1位小数点

10010110

00010110=22

2.2

10000011

00000011=3

3

10000000

 

PMap

10000001

00000001=1

1

11111111

1111111= -1

-1-1= -2(这里需要加上前一条消息的-1

=2位小数点

00010001,10011000

00010001=17

00011000=24

128*17+24=2200

2200+22=2222

考虑2位小数点=22.22

10000011

00000011=3

3

10000000

 

PMap

10000001

00000001=1

1

10000000

0000000=0

0-2= -2(这里需要加上前一条消息的-2

=2位小数点

01110111,10101001

11101110101001=-1111

2222-1111=1111

考虑2位小数点=11.11

10000011

00000011=3

3

 

从上述解析中可以看出,在进行浮点数传输时,如果使用了差值操作符,除了数值部分是差值传输,小数位数也是差值传输的,这一点非常容易搞错。

 

5、INCREMENT递增操作符

 

上述代码输出如下:

msg111= -> {123, 1, 2, 3}

msg111= -> {123, 1, 3, 3}

msg111= -> {123, 1, 4, 3}

outByteStr=11100000,11111011,10000001,10000010,10000011,10000000,10000001,10000011,10000000,10000001,10000011,

二进制数解析如下:

二进制数

解码过程

解码结果

11100000

 

PMap

11111011

01111011=123

123

10000001

00000001=1

1

10000010

00000010=2

2

10000011

00000011=3

3

10000000

 

PMap

10000001

00000001=1

1

10000011

00000011=3

3

10000000

 

PMap

10000001

00000001=1

1

10000011

00000011=3

3

 

可以看到,第二个字段在流中只发了一次初始值,第二条第三条由于是递增的数值,则不再发第二个字段。

 

问题:递减可以吗?

实测:不行

 

问题:只能递增1吗?

实测:是的

 

问题:浮点数可以递增吗?

实测:不行

 

6、NONE无操作符

就是没有操作符,流如实进行数据传输。

 

7、TAIL接尾操作符

 

上述代码输出如下:

msg111= -> {123, 1, 1234, 3}

msg111= -> {123, 1, 1235, 3}

msg111= -> {123, 1, 1236, 3}

outByteStr=11100000,11111011,10000001,00110001,00110010,00110011,10110100,10000011,10100000,10000001,10110101,10000011,10100000,10000001,10110110,10000011,

二进制数解析如下:

二进制数

解码过程

解码结果

11100000

 

PMap

11111011

01111011=123

123

10000001

00000001=1

1

00110001,00110010,00110011,10110100

00110001=49 > 1

00110010=50 > 2

00110011=51 > 3

00110100=52 > 4

1234

10000011

00000011=3

3

10100000

 

PMap

10000001

00000001=1

1

10110101

00110101=53 > 5

1235

10000011

00000011=3

3

10100000

 

PMap

10000001

00000001=1

1

10110110

00110110=54 > 6

1236

10000011

00000011=3

3

 

所谓的接尾,并不是在最后接起来,而是对于同样长度的字符串,只传递其“尾部变化”的部分。比如1234->1235,只传递5即可。

 

四、回顾

需要注意的点如下:

1、具备CONSTANT常量操作符的字段不能赋值

2、COPY复制操作符,指的是该字段若值不变,则流中不传输。但如果变了则还是传输。

3、DEFAULT默认操作符,会预先指定一个默认值,如果传输的值与默认值一致则流中不传输,如果要传输的值与默认值不一样则需要传输。

4、DELTA差值操作符,当数值增大或减小时,只传输增大或缩小的值,比如上一条数据传递的是10,本条传递的是+2,则实际传输值是12。需要注意对于浮点数DECIMAL,其小数点位数也是差值传递的,比如上一条数据是小数点后3位,本条传递的数据最终结果若是小数点后2位,则小数点位数这里应传递+1,这样上一条的-3(小数点后三位)加上这里传递的+1,最终结果是-2(小数点后2位)。

5、INCREMENT递增操作符,注意是只能更加而不能减少。

6、NONE无操作符,就是所有数据都正常传递,不做压缩

7、TAIL接尾操作符,需要注意的是,前后传递的字符串长度必须是一样的才能进行“接尾”,否则会如实传递全部数据。我感觉应该叫“换尾”操作符比较合适。比如1234->1235,这样值传递5即可。如果传递的是45,则最终解析结果就变成了1245。

 

posted @ 2023-08-24 16:49  布兰姥爷  阅读(96)  评论(0编辑  收藏  举报