zigzag压缩算法用于序列化无符号、有符号32位和64位整数。
TLV编码用于序列化字符串。
压缩算法zigzag
传输数据时将数据做压缩,以减少数据的传输量。因为在系统之间进行通讯时,往往需要以整型(int)或长整型(long)为基本的传输类型,以4字节或8字节来表示,这是如果传输一个比较小的整数时,会造成内存上的浪费。
算法思想
zigzag压缩思想是在传输过程中将整数中多余的0去掉(或者尽可能去掉无意义的0),传输有意义的1开始的数据。考虑到负数的存在,其具体实现为:
先求待压缩数据的补码,再将符号位的数移动到数据的最后一位,其它位往前挪一位,数据保持不变。如:
(-1)10
= (11111111_11111111_11111111_11111111)补
= (11111111_11111111_11111111_11111111)符号后移
= (00000000_00000000_00000000_00000001)zigzag
(1)10
= (00000000_00000000_00000000_00000001)补
= (00000000_00000000_00000000_00000010)符号后移
= (00000000_00000000_00000000_00000010)zigzag
代码实现
正变换
整数型值转换为zigzag值,其中n<<1是将整个值左移一位,n>>31将整个值右移31位将符号位放在最后一位,最后将左移和右移后的值进行异或操作。
int int_to_zigzag(int n)
{
return (n <<1) ^ (n >>31);
}
逆变换
将zigzag值还原为整型值,其中将数值对应的无符号数(不带符号)右移一位
int zigzag_to_int(int n)
{
return (((unsignedint)n) >>1) ^ -(n & 1);
}
压缩算法
将zigzag值传递给函数,该函数将这个值从低位到高位切分为7bits一组,若高位还有有效信息,则给这7bits补上1bit的1.如此反复直到前导全为0.
int write_to_buffer(int zz,byte* buf,int size)
{
int ret =0;
for (int i =0; i < size; i++)
{
if ((zz & (~0x7f)) ==0)//判断除低7位后有没有信息,若无
{
buf[i] = (byte)zz;//高位无信息,将最低位的一个字节保存
ret = i +1;
break;
}
else
{
buf[i] = (byte)((zz &0x7f) |0x80);//高位有信息,取最后的7位并在导数第八位补1
zz = ((unsignedint)zz)>>7;
}
}
return ret;
}
该压缩算法将多个字节的zigzag变换为较小字节数据后,在网络传输中将较小字节发送给对方进程,对方进程收到后会解压缩,进行还原组装。
解压缩算法
整个过程就和压缩的时候是逆向的:对于每一个字节,先看最高一位是否有1(0x80)。如果有,就说明不是最后一个数据字节包,那取这个字节的最后七位进行拼装。否则,说明就是已经到了最后一个字节了,那直接拼装后,跳出循环,算法结束。
int read_from_buffer(byte* buf,intmax_size)
{
int ret =0;
int offset =0;
for (int i =0; i < max_size; i++, offset +=7)
{
byte n = buf[i];
if ((n &0x80) !=0x80)
{
ret |= (n <<offset);
break;
}
else
{
ret |= ((n &0x7f) << offset);
}
}
return ret;
}
TLV编码
TLV编码为Type-Length-Value结构的数据编码格式,对于TCP/IP模型来说,TLV属于应用层协议,其可以自我嵌套,即一个TLV的value部分可以包含一个或多个TLV。
编码格式
Tag
描述了Value的数据类型,可由一个或两个字节组成。
length
描述了Value部分所占字节的个数,编码格式分为两类定长方式与不定长方式。
定长短形式:字节第7位为0,表示length中使用一个字节即可满足Value类型长度的描述,范围为0~127.
定长长形式:第一个字节的第7位为1,0-6为表示length所占字节数,将length值转为字节后附在其后,最多附4个字节。
不定长形式:Length所在八位组固定编码为0x80,但在Value编码结束后以两个0x00结尾。这种方式使得可以在编码没有完全结束的情况下,可以先发送部分数据给对方。
Value
由一个或多个值组成,值可以是一个原始数据类型(Primitive Data),也可以是一个TLV结构,即嵌套型(Constructed Data),其编码形式由tag首字节的第5位决定。
可以使用TLV编码器将网络报文转化为一个字节流,其后可通过各式网络进行发送,客户端在收到该字节流后需要解码获得相应信息。
变长编码varint
Varint是一种通过一个或多个字节来表示整数的方法,其可以通过可变的字节数来表示一个整数。
范围
Varint32:整型数经边长编码后占15个字节,即小的数用1个字节,大的数用5个字节;10个字节,小的数占用1个字节,大的数占用10个字节。
Varint64:整型数经边长编码后占用1
表示
msb:最高有效状态位,为1表示后面的字节属于当前数据(msb之后的7bits),为0表示当前字节(7bits)是最后一个字节数据。
有效数据位:每个边长编码字节用低7位来存储数字的二进制补码表示
举例
小端存储数据时,存储地址从左向右由低到高,字节从左到右为由低到高;因此将原数据每7位进行划分,将划分后的数据从右至左每7位按照Varint编码规则进行编码。
对于原数据最低7位放在编码后的最低地址,原数据中该7位之前的数据会放在该7位编码后的后面字节,原数据中之前数据有用,因此最低7位编码后的msb位为1;依次类推直至原数据当前编码的7位之前没有有用数据时msb位为0,且结束编码。
由以上编码规则可以看出,Varint编码可以起到压缩空间的作用。 blog.csdn.net/H514434485/…