Thrift服務端實現原理淺析

 

一. server端服務啓動流程  

  • 創建一個Processor(rpc_handler)實例,用於處理特定的輸入;
  • TBufferedTransportFactory用於數據傳輸;
  • threadManager.start()啓動服務線程;
  • Protocol表示數據傳輸的上層協議;

  • Server類用於接受客戶端請求。

二. threadManager.start()

這個方法主要用於啓動服務端的工作線程。

1. 調用addWorkder啓動workerCount_個工作線程;
a) 創建workerCount_ThreadManager::WorkerBoostThread相互引用。
b) 設置ThreadManager::Worker的狀態爲STARTING
c) 調用每個BoostThreadstart方法;
    i.
創建boost::thread,指定入口函數爲threadMain;
      ii. 設置BoostThread的狀態爲starting
d) BoostThread加入idMap中;
e) 等待所有的線程啓動完成。

2. boost::thread的入口函數threadMain()

threadMain()函數是工作線程的入口函數,主要功能是取得threadManager(std::set<Task*> tasks_;)中的task實例並進行處理,其具體實現步驟如下所示:

    從入口函數的參數中得到BoostThread指針;

    a) 設置BoostThread的狀態爲started;

    b) 調用ThreadManager::Workerstart方法,循環處理tasks_中的task;

    i. 檢查workerCount是否達到最大值;

 ii. 循環處理以下情況;

                1. 沒有task需要處理, manager_->monitor_.wait();等待處理task

                2. task需要處理,則取得task_中的第一個task,設置task的狀態爲EXECUTING,調用task->run()處理任務;

   c) 線程退出,設置BoostThread的狀態爲stopped

三. TThreadPoolServer.serv()

主線程:主要用於接收客戶端的請求並組成task並加入到threadManagertask_中,工作線程取得task並進行處理。 TThreadPoolServer.serv()的具體實現:

1. 調用serverTransport_->listten()方法,serverTransportserverSocket類型的對象。

a) 嘗試連接

b) 創建socketbindlisten.

2.  serverTransport_->accept(); 同步等待客戶端的連接,連接成功則轉到步驟3

3.  利用工廠得到transport對象和protocol對像;

4.  創建TThreadPoolServer::Task對象,傳入serverprocessorprotocoltransportclient對象:

server對象爲TThreadPoolServer類型,

processor對象爲FileStorageProcessor對象,

protocolTBinaryProtocol類型,

transport對象爲TBufferedTransport類型,都可以通過TThreadPoolServer構造函數配置。

client對象爲accept返回的socket

5.      TThreadPoolServer::Task對象插入到threadManager的任務隊列中;

a)  刪除過期的任務,本例中將過期時間設置爲0表明不過期;

b)  檢查pending 任務的數量是否超過最大值;

c)  task加到任務隊列中;

d)  如果有空閒的thread,就喚醒一個線程處理。

四. TThreadPoolServer::Task::run()

這個函數在工作線程中調用,主要作用:循環讀取消息頭,得到version,函數名和messageType,並且調用對應的處理函數得到輸出傳給客戶端,循環直到socket連接斷開。如果socket不斷開,就一直循環。
A. 循環讀取消息頭並處理

1. 得到EventHandlercallContext

2. 處理callContext

3. 循環調用FileStorageProcessor::process處理;
a) iprot->readMessageBegin(fname, mtype, seqid)得到函數名,MessageTypeseqid

            i.   result += readI32(sz);  得到version

            ii.  result += readStringBody(name, sz); 得到fname

            iii. result += readByte(type);   得到MessageType

4. 如果scoket連接中斷則則出循環

5. process_fn(iprot, oprot, fname, seqid, callContext); 調用特定的函數處理;

2
B.
Protocol怎樣從socket讀取數據
ReadI32讀取4個字節。readString會先讀取size4個字節),然後讀取string

具體步驟:

1. 建立結構體,便於轉換字節序;

2. 調用TBufferedTransport::readAll讀取4個字節,直接調用TBufferBase::readAll

a)  檢查rBuffer中是否有數據,有數據則直接中rBuffer中獲取;

b)  沒有數據則調用Transport::readAll

            i. 調用TBufferBase::read,檢查rBuffer中是否有數據,沒有則從socket中讀取,transport_就是保存的socket

            ii. 將讀取的數據轉換爲主機字節序。
C. 對應函數名的特定處理函數
函數名對應的處理函數存放在processMap_中,如”WriteFile”對應的處理函數爲processMap_["WriteFile"] = &FileStorageProcessor::process_WriteFile;
具體步驟:

1. 調用args.read(iprot);讀取參數

a) 調用readFieldBegin得到參數type和參數id

b) 得到參數的值

            i. 調用具體的RPC方法,並得到結果result.success

            ii. 調用oprot->writeMessageBegin("WriteFile", apache::thrift::protocol::T_REPLY, seqid);寫入messagetype

            iii. 調用result.write(oprot)寫入結果,通過socket傳輸。

閱讀(75) | 評論(1) | 轉發(0) |
0

上一篇:沒有了

下一篇:C++ STL map中的Key使用自定義類型

給主人留下些什麼吧!~~
12_avatar_small.jpg

7大爺2013-09-16 09:38:16

67.gif 學習

評論熱議
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章