基于protobuf的RPC实现
2015-08-12 16:19
405 查看
可以比较使用google protobuf RPC实现echo service可见。述。
google protobuf仅仅负责消息的打包和解包。并不包括RPC的实现。但其包括了RPC的定义。如果有以下的RPC定义:
那么要实现这个RPC须要最少做哪些事?总结起来须要完毕下面几步:
从server接收到网络消息。到调用到
解决方法就是在网络消息中带上RPC接口标识。
这个标识能够直接带上service name和method name,但这样的实现导致网络消息太大。还有一种实现是基于service name和method name生成一个哈希值,由于接口不会太多,所以较easy找到基本不冲突的字符串哈希算法。
不管哪种方法,server是肯定须要建立RPC接口标识到protobuf service对象的映射的。
这里提供第三种方法:基于option的方法。
protobuf中option机制类似于这样一种机制:service&method被视为一个对象,其有非常多属性,属性包括内置的,以及用户扩展的。用户扩展的就是option。每个属性有一个值。protobuf提供訪问service&method这些属性的接口。
首先扩展service&method的属性。下面定义这些属性的key:
应用层定义service&method时能够指定以上key的值:
以上相当于在整个应用中。每一个service都被赋予了唯一的id,单个service中的method也有唯一的id。
然后能够通过protobuf取出以上属性值:
考虑到
然后就能够把这个值作为网络消息头的一部分发送。
当然server端是须要建立这个标识值到service的映射的:
服务端收到RPC调用后,取出这个标识值,然后再从
protobuf extensions
protobuf service
protobuf options
原文地址: http://codemacro.com/2014/08/31/protobuf-rpc/
written by Kevin Lynx posted at
http://codemacro.com
google protobuf仅仅负责消息的打包和解包。并不包括RPC的实现。但其包括了RPC的定义。如果有以下的RPC定义:
service MyService { rpc Echo(EchoReqMsg) returns(EchoRespMsg) }
那么要实现这个RPC须要最少做哪些事?总结起来须要完毕下面几步:
client
RPCclient须要实现google::protobuf::RpcChannel。主要实现
RpcChannel::CallMethod接口。client调用不论什么一个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) { ... DataBufferOutputStream outputStream(...) // 取决于你使用的网络实现 request->SerializeToZeroCopyStream(&outputStream); _connection->postData(outputStream.getData(), ... ... }
服务端
服务端首先须要实现RPC接口。直接实现MyService中定义的接口:
class MyServiceImpl : public MyService { virtual void Echo(::google::protobuf::RpcController* controller, const EchoReqMsg* request, EchoRespMsg* response, ::google::protobuf::Closure* done) { ... done->Run(); } }
标示service&method
基于以上,能够看出服务端根本不知道client想要调用哪一个RPC接口。从server接收到网络消息。到调用到
MyServiceImpl::Echo还有非常大一段距离。
解决方法就是在网络消息中带上RPC接口标识。
这个标识能够直接带上service name和method name,但这样的实现导致网络消息太大。还有一种实现是基于service name和method name生成一个哈希值,由于接口不会太多,所以较easy找到基本不冲突的字符串哈希算法。
不管哪种方法,server是肯定须要建立RPC接口标识到protobuf service对象的映射的。
这里提供第三种方法:基于option的方法。
protobuf中option机制类似于这样一种机制:service&method被视为一个对象,其有非常多属性,属性包括内置的,以及用户扩展的。用户扩展的就是option。每个属性有一个值。protobuf提供訪问service&method这些属性的接口。
首先扩展service&method的属性。下面定义这些属性的key:
extend google.protobuf.ServiceOptions { required uint32 global_service_id = 1000; } extend google.protobuf.MethodOptions { required uint32 local_method_id = 1000; }
应用层定义service&method时能够指定以上key的值:
service MyService { option (arpc.global_service_id) = 2302; rpc Echo(EchoReqMsg) returns(EchoRespMsg) { option (arpc.local_method_id) = 1; } rpc Echo_2(EchoReqMsg) returns(EchoRespMsg) { option (arpc.local_method_id) = 2; } ... }
以上相当于在整个应用中。每一个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) { ... google::protobuf::ServiceDescriptor *service = method->service(); uint32_t serviceId = (uint32_t)(service->options().GetExtension(global_service_id)); uint32_t methodId = (uint32_t)(method->options().GetExtension(local_method_id)); ... }
考虑到
serviceId
methodId的范围,能够直接打包到一个32位整数里:
uint32_t ret = (serviceId << 16) | methodId;
然后就能够把这个值作为网络消息头的一部分发送。
当然server端是须要建立这个标识值到service的映射的:
bool MyRPCServer::registerService(google::protobuf::Service *rpcService) { const google::protobuf::ServiceDescriptor = rpcService->GetDescriptor(); int methodCnt = pSerDes->method_count(); for (int i = 0; i < methodCnt; i++) { google::protobuf::MethodDescriptor *pMethodDes = pSerDes->method(i); uint32_t rpcCode = PacketCodeBuilder()(pMethodDes); // 计算出映射值 _rpcCallMap[rpcCode] = make_pair(rpcService, pMethodDes); // 建立映射 } 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);
參考
使用google protobuf RPC实现echo serviceprotobuf extensions
protobuf service
protobuf options
原文地址: http://codemacro.com/2014/08/31/protobuf-rpc/
written by Kevin Lynx posted at
http://codemacro.com
相关文章推荐
- 国王的烦恼---nyoj
- 1314祝福语
- vs2013调试时总是要加载公共符号
- 1314祝福语
- IBM HTTP Server https configuration
- 查税
- HDOJ 题目3308 LCIS(线段树,区间查询,区间合并)
- Mongdb介绍篇
- HDU 5371 Hotaru's problem Manacher+线段树
- django 模板
- 在 Visual C++ 中以错误的顺序链接 CRT 库和 MFC 库时出现 LNK2005 错误
- ScrollView自动从顶部显示
- NOIP2013模拟10.23轮舞前夕
- hdu 2120 Ice_cream's world I (简单并查集 + 判环)
- SQLite集成与用法
- [独孤九剑]持续集成实践(三)- Jenkins安装与配置(Jenkins+MSBuild+GitHub)
- hdu 2120 Ice_cream's world I (简单并查集 + 判环)
- poj3318--Matrix Multiplication(随机算法)
- 详细解读JavaScript的跨浏览器事件处理
- 20150812-IAR环境报Fatal Error[Cp001]: Copy protection check, No valid license found for this product