Thrift之Protocol原始碼分析
之前寫過兩篇關於 Thrift 的相關文章。
也算是對Thrift比較熟悉,不過對 Thrift 裡面的 Protocol 部分還是黑盒使用。 雖然大概能猜到具體實現方式,但是還是忍不住花了一點點時間把具體程式碼實現翻出來看看。 主要是為了滿足一下好奇心。
簡單搞了一個Thrift的描述檔案Insight.thrift作為例子。
struct Person {
1: string name,
2: i32 age,
3: optional string address,
}
service Insight {
Person Hello(1: Person person),
Person Hi(1: Person p1, 2: Person p2),
}
然後通過 畢竟Thrift其實就是幹RPC的活,所以看原始碼就按著RPC遠端呼叫的順序來看就行。
從Hello函式呼叫開始,InsightClient::Hello 可以看出, 在每次RPC呼叫的時候,會先將函式名通過writeMessageBegin(“Hello”,
::apache::thrift::protocol::T_CALL, cseqid) 先傳送過去。 這個過程的序列化協議很簡單,直接就是傳輸的函式名字串。 然後再傳送引數。 傳送引數的時候,會將所有引數作為一個 struct 傳送
Insight_Hello_pargs,
所以協議的序列化過程主要都是體現在 struct 的序列化上面。 比如像Hi函式的引數序列化過程:
uint32_t Insight_Hi_pargs::write(::apache::thrift::protocol::TProtocol* oprot) const {
uint32_t xfer = 0;
xfer += oprot->writeStructBegin("Insight_Hi_pargs");
xfer += oprot->writeFieldBegin("p1", ::apache::thrift::protocol::T_STRUCT, 1);
xfer += (*(this->p1)).write(oprot);
xfer += oprot->writeFieldEnd();
xfer += oprot->writeFieldBegin("p2", ::apache::thrift::protocol::T_STRUCT, 2);
xfer += (*(this->p2)).write(oprot);
xfer += oprot->writeFieldEnd();
xfer += oprot->writeFieldStop();
xfer += oprot->writeStructEnd();
return xfer;
}
整個物件的序列化過程主要是依賴了介面 TProtocol 的函式。
對於實現 TProtocol 介面的序列化實現主要是以下三種(在thrift-0.9.0/lib/cpp/src/thrift/protocol
裡):
- TBinaryProtocol
- TCompactProtocol
- TJSONProtocol
要了解協議序列化過程主要看一下 TBinaryProtocol 和 TCompactProtocol 就夠了。
主要是如下幾個關鍵點:
- 其實 writeStructStruct 和 writeStructEnd 啥屁事也不用做。
- 其實 writeFieldBegin 只有後兩個引數有用,第二個引數是型別,第三個引數是ID, 因為光靠這兩者就可以在反序列化(讀取解析)的時候知道是哪個成員了。
- struct write 的過程其實是個遞迴的過程,也就是在write函式中, 會遞迴的呼叫結構體本身每個成員的write函式。
- TCompactProtocol 和 TBinaryProtocol 的區別主要是, TCompactProtocol 對整數型別使用了 ZigZag 壓縮演算法,比如 i32 型別的整數本來是4個位元組, 可以壓縮成 1~5 位元組不等。而 i64型別的整數本來是8個位元組。可以壓縮成 1~10 位元組不等。
http://yanyiwu.com/work/2015/04/05/thrift-protocol-insight.html
相關文章
- Tomcat原始碼分析2 之 Protocol實現分析Tomcat原始碼Protocol
- thrift原始碼分析-架構設計原始碼架構
- Storm-原始碼分析-Thrift的使用ORM原始碼
- Guava 原始碼分析之 EventBus 原始碼分析Guava原始碼
- Android 原始碼分析之 AsyncTask 原始碼分析Android原始碼
- Runtime原始碼 protocol(協議)原始碼Protocol協議
- 原始碼分析之 HashMap原始碼HashMap
- 原始碼分析之AbstractQueuedSynchronizer原始碼
- 原始碼分析之ArrayList原始碼
- 原始碼|jdk原始碼之HashMap分析(一)原始碼JDKHashMap
- 原始碼|jdk原始碼之HashMap分析(二)原始碼JDKHashMap
- redis原始碼分析(二)、redis原始碼分析之sds字串Redis原始碼字串
- 死磕 jdk原始碼之HashMap原始碼分析JDK原始碼HashMap
- JUC之CountDownLatch原始碼分析CountDownLatch原始碼
- Dubbo之SPI原始碼分析原始碼
- Fresco原始碼分析之DraweeView原始碼View
- lodash原始碼分析之isArguments原始碼
- Fresco原始碼分析之Hierarchy原始碼
- 原始碼分析Kafka之Producer原始碼Kafka
- RecyclerView之SnapHelper原始碼分析View原始碼
- OpenGL 之 GPUImage 原始碼分析GPUUI原始碼
- lodash原始碼分析之isObjectLike原始碼Object
- 原始碼分析之 LinkedList原始碼
- Envoy原始碼分析之Dispatcher原始碼
- Redux原始碼分析之createStoreRedux原始碼
- MongoDB原始碼分析之MongosXFMongoDB原始碼
- jdk原始碼分析之TreeMapJDK原始碼
- 原始碼分析之ThreadPoolExecutor原始碼thread
- Spark原始碼分析之MemoryManagerSpark原始碼
- Spark原始碼分析之BlockStoreSpark原始碼BloC
- bootstrap原始碼分析之Carouselboot原始碼
- Bootstrap原始碼分析之dropdownboot原始碼
- jdk原始碼分析之PriorityQueueJDK原始碼
- jdk原始碼分析之WeakHashMapJDK原始碼HashMap
- jdk原始碼分析之ArrayListJDK原始碼
- jdk原始碼分析之HashMapJDK原始碼HashMap
- jdk原始碼分析之CopyOnWriteArrayListJDK原始碼
- DRF之Response原始碼分析原始碼