Thrift的TProtocol類體系原理及源碼詳解:緊湊協議類TCompactProtocolT(TCompactProtocol)
這個協議類採用了zigzag 編碼,這種編碼是基於Variable-length quantity編碼提出來 的,因為Variable-length quantity編碼對於負數的編碼都需要很長的位元組數,而zigzag 編 碼對於絕對值小的數字,無論正負都可以採用較少的位元組來表示,充分利用了 Varint技術。 所以這個協議類採用zigzag 編碼可以節省傳輸空間,使資料的傳輸效率更高。至於zigzag具 體的編碼實現方式可以網上查查,其實就是把從低位到最後一個還存在1(二進位)的最高位 表示出來就可以了。這個協議類對外提供的方法和上面介紹的二進位協議相同,這樣可以很 方便使用者從一種協議改變到另一種協議。
下面我同樣結合scribe提供的Log方法來 分析這個協議類的功能,不過不會像上面二進位協議在把整個過程分析了,我只會分析與協 議相關的部分了,分析一些比較難懂的一些函數功能,分析的思路還是按照函數調用過程來 分析。
首先還是分析writeMessageBegin函數,下面是這個函數的實現代碼:
template <class Transport_> uint32_t TCompactProtocolT<Transport_>::writeMessageBegin( const std::string& name, const TMessageType messageType, const int32_t seqid) { uint32_t wsize = 0; wsize += writeByte(PROTOCOL_ID);//寫入這個協議的產品ID號:為0x82 wsize += writeByte((VERSION_N & VERSION_MASK) | (((int32_t)messageType << TYPE_SHIFT_AMOUNT) & TYPE_MASK));//寫入此協議的版本號碼和訊息類型:前3位是訊息類型,後面5位是協議版本號碼 wsize += writeVarint32(seqid);//寫入請求序號 wsize += writeString(name);//寫入訊息名稱(也就是函數調用名稱) return wsize;//返回寫入的大小,多少位元組 }
因為這些協議類都是模板類,所以每一個函數也就是模板函數了。函數具體的功 能代碼裡有詳細注釋,其中的writeByte函數就是寫入一個位元組到伺服器。這裡與二進位協議 不同的是這裡寫入請求序號(也就是對於所有的整型數)都調用的writeVarint32函數,這 個函數就是採用zigzag編碼寫入整型數到伺服器,代碼如下:
template <class Transport_> uint32_t TCompactProtocolT<Transport_>::writeVarint32(uint32_t n) { uint8_t buf[5];//對於一個整數,zigzag編碼最大採用5個位元組儲存 uint32_t wsize = 0; while (true) { if ((n & ~0x7F) == 0) {//判斷除了最低7位是否還有其他高位為1(二進位) buf[wsize++] = (int8_t)n;//沒有了代表著就是最後一個位元組 break;//退出迴圈 } else { buf[wsize++] = (int8_t)((n & 0x7F) | 0x80);//取最低7位加上第8位(為1代表後續還有位元組屬於這個整數,為0代表這是這個整數的最後一個位元組了。 n >>= 7;//移走已經編碼的位元 } } trans_->write(buf, wsize);//寫入編碼的位元組數 return wsize;//返回寫入的位元組數 }