RPC作為一種特殊的網絡編程,會封裝一層傳輸層來支持底層的網絡通信。Thrift使用了Transport來封裝傳輸層,但Transport不僅僅是底層網絡傳輸,它還是上層流的封裝。
關于Transport的設計,從架構上看,IO流和網絡流都是IO的范疇,用一個統一的接口來抽象并無不可,但是個人感覺看Thrift的代碼時,都用的Transport來表示流,不知道是普通IO流還是底層的網絡流。還不如用Java的方式,把普通IO和網絡接口用不同抽象隔離,至少代碼邏輯比較清晰
廢話不多說,看看Trasport的類結構。 TTransport作為頂層的抽象,使用了抽象類,沒有使用接口。個人感覺這種做法還是沒有使用接口作為頂層抽象來得好,接口擴展性更好。
有幾個關注點:
1. TIOStreamTransport和TSocket這兩個類的結構對應著阻塞同步IO, TSocket封裝了Socket接口
2. TNonblockingTrasnsort,TNonblockingSocket這兩個類對應著非阻塞IO
3. TMemoryInputTransport封裝了一個字節數組byte[]來做輸入流的封裝
4. TMemoryBuffer使用字節數組輸出流ByteArrayOutputStream做輸出流的封裝
5. TFramedTransport則封裝了TMemoryInputTransport做輸入流,封裝了TByteArryOutPutStream做輸出流,作為內存讀寫緩沖區的一個封裝。TFramedTransport的flush方法時,會先寫4個字節的輸出流的長度作為消息頭,然后寫消息體。和FrameBuffer的讀消息對應起來。FrameBuffer對消息時,先讀4個字節的長度,再讀消息體
6. TFastFramedTransport是內存利用率更高的一個內存讀寫緩存區,它使用自動增長的byte[](不夠長度才new),而不是每次都new一個byte[],提高了內存的使用率。其他和TFramedTransport一樣,flush時也會寫4個字節的消息頭表示消息長度。

和Java的IO一樣,Thrift的Transport也采用了裝飾器模式實現了所謂的包裝流。我們也使用包裝流和節點流的概念來區分一下各個Transport。
節點流表示自身采用byte[]來提供IO讀寫的類:
AutoExpandingBufferReadTransport
AutoExpandingBufferWriteTransport
TMemoryInputTransport
TByteArrayOutputStream
TMemoryBuffer
兩個網絡相關的比較特殊,我們也可以認為它們是節點流,它們是直接操作網絡讀寫的對象
TNonblockingSocket
TSocket
包裝流表示封裝了其他Transport,流來提供IO讀寫的類:
TFramedTransport
TFastFramedTransport
Thrift提供的包裝流主要就是兩個以TFrame開頭的Transort,這兩個Transport在寫完消息flush的時候,會加上4字節表示長度的消息頭,讀消息是會先讀4字節表示長度的消息頭。
既然Thrift的NIO服務器端讀消息時,使用了FrameBuffer來做緩沖區,并且解碼時先讀4字節長度的消息頭,那么可以推斷出,客戶端發消息時,是使用TFramedXXXTransport包裝流來傳輸數據的。
我們來一個實際的客戶端對象構造情況
~~~
TSocket socket = new TSocket(host, port);
socket.setTimeout(timeout);
TTransport transport = new TFramedTransport(socket);
TProtocol protocol = new TCompactProtocol(transport);
transport.open();
~~~
另外我們在講Thrift協議的時候說了,Thrift的協議是和具體的傳輸對象綁定的,協議使用具體的Transport來讀寫數據