版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、Good is good, but better carries it.精益求精,善益求善。Thrift之TProtocol类体系原理及源码详细解析之紧凑协议类TCompactProtocolTTCompactProtocol-这个协议类采用了zigzag编码,这种编码是基于Variable-lengthquantity编码提出来的,因为Variable-lengthquantity编码对于负数的编码都需要很长的字节数,而zigzag编码对于绝对值小的数字,无论正负都可以采用较少的字节来表示,充分利用了Varint技术。所以这个协议类采用zigzag编码可以节省传输空间,使数据的传输效率更高。
2、至于zigzag具体的编码实现方式可以网上查查,其实就是把从低位到最后一个还存在1(二进制)的最高位表示出来就可以了。这个协议类对外提供的方法和上面介绍的二进制协议相同,这样可以很方便使用者从一种协议改变到另一种协议。下面我同样结合scribe提供的Log方法来分析这个协议类的功能,不过不会像上面二进制协议在把整个过程分析了,我只会分析与协议相关的部分了,分析一些比较难懂的一些函数功能,分析的思路还是按照函数调用过程来分析。首先还是分析writeMessageBegin函数,下面是这个函数的实现代码:1templateuint32_tTCompactProtocolT:writeMessage
3、Begin(23conststd:string&name,constTMessageTypemessageType,constint32_tseqid)45uint32_twsize=0;67wsize+=writeByte(PROTOCOL_ID);/写入这个协议的产品ID号:为0 x8289wsize+=writeByte(VERSION_N&VERSION_MASK)|(int32_t)messageTypeTYPE_SHIFT_AMOUNT)&TYPE_MASK);/写入此协议的版本号和消息类型:前3位是消息类型,后面5位是协议版本号10HYPERLINK11wsize+=writeV
4、arint32(seqid);/写入请求序列号1213wsize+=writeString(name);/写入消息名称(也就是函数调用名称)1415returnwsize;/返回写入的大小,多少字节1617因为这些协议类都是模板类,所以每一个函数也就是模板函数了。函数具体的功能代码里有详细注释,其中的writeByte函数就是写入一个字节到服务器。这里与二进制协议不同的是这里写入请求序列号(也就是对于所有的整型数)都调用的writeVarint32函数,这个函数就是采用zigzag编码写入整型数到服务器,代码如下:1templateuint32_tTCompactProtocolT:write
5、Varint32(uint32_tn)23uint8_tbuf5;/对于一个整数,zigzag编码最大采用5个字节保存45uint32_twsize=0;67while(true)89if(n&0 x7F)=0)/判断除了最低7位是否还有其他高位为1(二进制)1011bufwsize+=(int8_t)n;/没有了代表着就是最后一个字节1213break;/退出循环1415else1617bufwsize+=(int8_t)(n&0 x7F)|0 x80);/取最低7位加上第8位(为1代表后续还有字节属于这个整数,为0代表这是这个整数的最后一个字节了。1819n=7;/移走已经编码的位数202
6、122232425trans_-write(buf,wsize);/写入编码的字节数26HYPERLINK27returnwsize;/返回写入的字节数2829这个函数的功能就是对整数进行Variable-lengthquantity编码后写入,如果为负数需要处理。如果不处理那么每一个负数都需要5个字节来编码,因为最高位表示符号位,而负数的符号位用1表示(也就是说负数的最高位永远为1)。处理的方式也很简单(就是zigzag编码),就是把最高位(符号位)移动到最低位,最低位到次高位一次向高位移动一位,代码如下(就一句就实现了):1template23uint32_tTCompactProtoco
7、lT:i32ToZigzag(constint32_tn)45return(n31);67上面写入整数和处理负数都是针对的32位的,当然也有64位的相应函数,实现方式相同。我们在回到writeMessageBegin函数,里面还有一个writeString函数用来写入一个字符串的,与二进制不同的是写入字符串长度也是采用了可变长度编码的方式写入,然后写入字符串的具体数据,它是调用另一个函数writeBinary写入,writeBinary实现代码如下:1template23uint32_tTCompactProtocolT:writeBinary(conststd:string&str)45ui
8、nt32_tssize=str.size();67uint32_twsize=writeVarint32(ssize)+ssize;/写入字符串的长度并计算写入的长度(包括字符串的长度)89trans_-write(uint8_t*)str.data(),ssize);/写入字符串的数据1011returnwsize;1213写消息函数分析完毕以后我们在来看看对应的读消息函数readMessageBegin,看这个函数必须和写入消息的函数对应起来看,不然就不能理解它读取和处理的流程代码,具体实现如下代码:1templateuint32_tTCompactProtocolT:readMessag
9、eBegin(23std:string&name,TMessageType&messageType,int32_t&seqid)45uint32_trsize=0;67int8_tprotocolId;89int8_tversionAndType;1011int8_tversion;1213rsize+=readByte(protocolId);/读取协议产品ID号1415if(protocolId!=PROTOCOL_ID)/判断是不是这个协议的产品ID号,不是就抛出异常1617throwTProtocolException(TProtocolException:BAD_VERSION,Ba
10、dprotocolidentifier);18192021rsize+=readByte(versionAndType);/读取此协议的版本号和消息类型2223version=(int8_t)(versionAndType&VERSION_MASK);/取出协议版本号2425if(version!=VERSION_N)/判断是不是对应的协议版本号,不是抛出异常2627throwTProtocolException(TProtocolException:BAD_VERSION,Badprotocolversion);28293031messageType=(TMessageType)(versi
11、onAndTypeTYPE_SHIFT_AMOUNT)&0 x03);/取出消息类型3233rsize+=readVarint32(seqid);/读取请求序列号3435rsize+=readString(name);/读取消息名称(函数名称)3637returnrsize;/返回读取的长度(字节)3839通过对照写入消息的函数就很容易理解,因为你写入什么我就读什么并且判断是不是相同协议写入的,具体分析可以看上面的代码和详细的注释。而且还有一点就是具体的写入数据类型的函数也是采用对应类型的读函数,例如读可变长整型写入就是采用可变长读函数readVarint32,写字符串对应读字符串函数read
12、String,对照相应的写入函数来看这些读数据函数就非常好理解了,就不具体分析这些读函数了。下面在分析几个复合数据类型的写入函数,因为这些写入函数存在一定技巧不容易(或者说不那么直观吧)理解清楚。首先看看struct类型的数据写入的过程,它分为写入开始、中间处理和写入结束。下面是开始写入struct的代码:1template23uint32_tTCompactProtocolT:writeStructBegin(constchar*name)45(void)name;67lastField_.push(lastFieldId_);/把最后写入的字段ID压入堆栈89lastFieldId_=0;
13、/重新设置为01011return0;1213这开始写入的函数没有做什么具体的工作,只是把最后写入的字段ID压入堆栈,这样做的目的是处理那种struct嵌套的数据结构类型。Struct里面的是一个一个的字段,所以根据struct的字段个数分别调用字段写入函数依次写入,字段写入函数定义如下:1templateint32_tTCompactProtocolT:writeFieldBeginInternal(23constchar*name,constTTypefieldType,constint16_tfieldId,int8_ttypeOverride)45(void)name;/为了防止编译器
14、产生警告信息67uint32_twsize=0;89/如果存在对于对应的类型就转换为对应的1011int8_ttypeToWrite=(typeOverride=-1?getCompactType(fieldType):typeOverride);1213/检查字段ID是否使用了增量编码1415if(fieldIdlastFieldId_&fieldId-lastFieldId_=15)/如果使用了增量编码并增量且小于等于151617wsize+=writeByte(fieldId-lastFieldId_)4|typeToWrite);/字段ID和数据类型一起写入1819else/否则单独写
15、入2021wsize+=writeByte(typeToWrite);/写入数据类型2223wsize+=writeI16(fieldId);/写入字段ID24252627lastFieldId_=fieldId;/保存写入字段ID为最后一个写入的ID2829returnwsize;/返回写入的长度3031当结构体里面的每一个字段都写入以后还需要调用writeStructEnd函数来处理结束一个struct的写入,主要处理是字段ID的相关内容,实现代码如下:1templateuint32_tTCompactProtocolT:writeStructEnd()23lastFieldId_=las
16、tField_.top();/取得最后一次压入堆栈的字段ID号45lastField_.pop();/弹出以取得的字段ID67return0;89同样的结构体也有对应的读取函数,具体实现就不在具体分析了!下面继续分析一些特殊的处理代码,首先看看负数在进行zigzag编码前怎样处理,对于32位和64位都是一句代码就搞定,如下代码:1return(n1)-(n&1);这句代码的作用就是把最高位的符号位移动到最低位,然后最低位到次高位依次向高位移动一位,这样就避免了所有负数都需要最长的字节来编码。在看看读可变长编码写入整型数的函数,32位和64位都是相同的实现,因为32位也是调用64位的函数实现的,
17、实现代码如下:1templateuint32_tTCompactProtocolT:readVarint64(int64_t&i64)23uint32_trsize=0;45uint64_tval=0;67intshift=0;89uint8_tbuf10;/64位采用zigzag编码最长可能是10字节1011uint32_tbuf_size=sizeof(buf);1213constuint8_t*borrowed=trans_-borrow(buf,&buf_size);/并不是所有transport都支持1415if(borrowed!=NULL)/快路径,要读的数据已经在缓存中1617
18、while(true)1819uint8_tbyte=borrowedrsize;2021rsize+;2223val|=(uint64_t)(byte&0 x7f)consume(rsize);/消耗了多少字节,即表示这个编码用了多少字节3233returnrsize;34353637/检查编码数据是否超过了最长限制,是就抛出一个无效的异常3839if(UNLIKELY(rsize=sizeof(buf)4041throwTProtocolException(TProtocolException:INVALID_DATA,Variable-lengthintover10bytes.);4243444546474849else/慢路径,要读的数据还没有存在缓存中5051while(true)5253uint8_tbyte;5455rsize+=trans_-readAll(&byte,1);/读取一个字节5657val|=(uint64_t)(byte&0 x7f)=sizeof(buf)/同样检查数据的有效性:最大字节长度不超过10个字节7071throwTProtocolException(TProtocolException:INVA
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2026年睡眠与心理健康教育课件(知识竞赛版)
- 2025《行政处罚法》知识试题库及参考答案(版)
- 2026中国华电校招笔试题及答案
- 2026季度目标达成与收支复盘
- 2026 年教师节教师心理健康维护职业压力疏导课件
- 2026 年关爱老年人践行孝善文化教育课件
- 广东省2026年初中学业水平考试数学模拟卷附答案
- 飞机试飞设备安装调试工操作规程测试考核试卷含答案
- 音乐资格考试试题及答案
- 转底炉工岗前安全演练考核试卷含答案
- 房产继承分配协议书5篇
- 2026年天津市辅警招聘考试试题带答案(精练)
- 人防工程机电设备安装施工技术方案
- 《房地产信托投融资实务及典型案例》目录
- 2026农机行业市场深度研究及行业竞争与技术创新发展趋势报告
- 2026年成人高考专升本《政治》真题(含答案)
- 侵害未成年案件强制报告制度培训课件
- 电网检修工程预算定额(2020年版)全5册excel版
- 生产过程中次品管理制度
- XXX氨制冷安装工程施工方案
- 2026《高一数学培优讲义》秋季(学生版)
评论
0/150
提交评论