1. 程式人生 > >Thrift原始碼分析(六)-- Transport傳輸層分析

Thrift原始碼分析(六)-- Transport傳輸層分析

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來讀寫資料