可以對照使用google protobuf rpc實現echo service一文看,細節本文不再描述。
google protobuf只負責訊息的打包和解包,並不包含rpc的實現,但其包含了rpc的定義。假設有下面的rpc定義:
service
myservice
那麼要實現這個rpc需要最少做哪些事?總結起來需要完成以下幾步:
rpc客戶端需要實現google::protobuf::rpcchannel
。主要實現rpcchannel::callmethod
介面。客戶端呼叫任何乙個rpc介面,最終都是呼叫到callmethod
。這個函式的典型實現就是將rpc呼叫引數序列化,然後投遞給網路模組進行傳送。
void
callmethod
(const
::google
::protobuf
::methoddescriptor
*method,::
google
::protobuf
::rpccontroller
*controller
,const
::google
::protobuf
::message
*request,::
google
::protobuf
::message
*response,::
google
::protobuf
::closure
*done
)
服務端首先需要實現rpc介面,直接實現myservice
中定義的介面:
class
myserviceimpl
:public
myservice
}
基於以上,可以看出服務端根本不知道客戶端想要呼叫哪乙個rpc介面。從伺服器接收到網路訊息,到呼叫到myserviceimpl::echo
還有很大一段距離。
解決方法就是在網路訊息中帶上rpc介面標識。這個標識可以直接帶上service name和method name,但這種實現導致網路訊息太大。另一種實現是基於service name和method name生成乙個雜湊值,因為介面不會太多,所以較容易找到基本不衝突的字串雜湊演算法。
無論哪種方法,伺服器是肯定需要建立rpc介面標識到protobuf service物件的對映的。
這裡提供第三種方法:基於option的方法。
protobuf中option機制類似於這樣一種機制:service&method被視為乙個物件,其有很多屬性,屬性包含內建的,以及使用者擴充套件的。使用者擴充套件的就是option。每乙個屬性有乙個值。protobuf提供訪問service&method這些屬性的介面。
首先擴充套件service&method的屬性,以下定義這些屬性的key:
extend
google
.protobuf
.serviceoptions
extend
google
.protobuf
.methodoptions
應用層定義service&method時可以指定以上key的值:
service
myservice
rpcecho_2
(echoreqmsg
)returns
(echorespmsg
)...
}
以上相當於在整個應用中,每個service都被賦予了唯一的id,單個service中的method也有唯一的id。
然後可以通過protobuf取出以上屬性值:
void
callmethod
(const
::google
::protobuf
::methoddescriptor
*method,::
google
::protobuf
::rpccontroller
*controller
,const
::google
::protobuf
::message
*request,::
google
::protobuf
::message
*response,::
google
::protobuf
::closure
*done
)
考慮到serviceid
methodid
的範圍,可以直接打包到乙個32位整數裡:
uint32_t ret = (serviceid << 16) | methodid;
然後就可以把這個值作為網路訊息頭的一部分傳送。
當然伺服器端是需要建立這個標識值到service的對映的:
bool
myrpcserver
::registerservice
(google
::protobuf
::service
*rpcservice
)return
true
;}
服務端收到rpc呼叫後,取出這個標識值,然後再從_rpccallmap
中取出對應的service和method,最後進行呼叫:
google
::protobuf
::message
*response
=_pservice
->
getresponseprototype
(_pmethoddes
).new
();// 用於回應的closure
rpcserverclosure
*pclosure
=new
(nothrow
)rpcserverclosure
(_channelid
,_pconnection
,_preqmsg
,presmsg
,_messagecodec
,_version
);rpccontroller
*pcontroller
=pclosure
->
getrpccontroller
();...
// protobuf 生成的callmethod,會自動呼叫到echo介面
_pservice
->
callmethod
(_pmethoddes
,pcontroller
,_preqmsg
,presmsg
,pclosure
);
RESTful還是基於HTTP的RPC實現
比如說,這個restful風格。從網上的資料大概知道,它首次出現在 2000 年 roy fielding 的博士 中,他是 http 規範的主要編寫者之一。對於http來作為通訊,我認為是乙個不錯的方案,因為目前大多語言的標準庫應該都是提供了http的支援,而且http這種無狀態的請求,也容易接受...
基於MQTT的RPC協議
rpc 是一種基於request response 模式的分布式協議。而mqtt 是基於pub sub模式的協議。是否能夠將這兩種協議相結合,實現rpc over mqtt 我並沒有發現由比較知名的rpc over mqtt協議。於是,自己著手設計乙個極簡的rpc over mqtt 協議。本文介紹...
RabbitMQ 基於RPC實現
對於使用rabbitmq執行command的情況,有時候需要有返回值資訊。此時相當於client發布乙個command後,並偵聽返回結果的queue,server接收並處理,將處理結果發布到client偵聽的queue中。簡單實現如下 1.client端 private static void rp...