可以比较使用google protobuf RPC实现echo service可见。述。

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);

參考

原文地址: http://codemacro.com/2014/08/31/protobuf-rpc/

written by Kevin Lynx  posted at
http://codemacro.com

版权声明:本文博客原创文章,博客,未经同意,不得转载。

基于protobuf的RPC实现的更多相关文章

  1. RPC框架实现(一) Protobuf的rpc实现

    概述 RPC框架是云端服务基础框架之一,负责云端服务模块之间的项目调用,类似于本地的函数调用一样方便.常见的RPC框架配带的功能有: 编解码协议.比如protobuf.thrift等等. 服务发现.指 ...

  2. 基于HTTP/2和protobuf的RPC框架:GRPC

    谷歌发布的首款基于HTTP/2和protobuf的RPC框架:GRPC Google 刚刚开源了grpc,  一个基于HTTP2 和 Protobuf 的高性能.开源.通用的RPC框架.Protobu ...

  3. 基于Protobuf的分布式高性能RPC框架——Navi-Pbrpc

    基于Protobuf的分布式高性能RPC框架——Navi-Pbrpc 二月 8, 2016 1 简介 Navi-pbrpc框架是一个高性能的远程调用RPC框架,使用netty4技术提供非阻塞.异步.全 ...

  4. 基于Netty打造RPC服务器设计经验谈

    自从在园子里,发表了两篇如何基于Netty构建RPC服务器的文章:谈谈如何使用Netty开发实现高性能的RPC服务器.Netty实现高性能RPC服务器优化篇之消息序列化 之后,收到了很多同行.园友们热 ...

  5. 基于kryonet的RPC,使用kryo进行序列化

    Kryo是一个序列化框架. Kryonet是一个基于kryo的RPC框架,它实现了一套高效简洁的API,它通过NIO实现了TCP和UDP通讯,目前还不支持Http. 自己写了一个测试代码,运行了下,感 ...

  6. github上的golang双向rpc,基于原生“net/rpc”库实现,可以注册回调

    github上的golang双向rpc,基于原生“net/rpc”库实现,可以注册回调.仅支持一个server和一个client交互. 地址:https://github.com/rocket049/ ...

  7. 基于Netty的RPC简易实现

    代码地址如下:http://www.demodashi.com/demo/13448.html 可以给你提供思路 也可以让你学到Netty相关的知识 当然,这只是一种实现方式 需求 看下图,其实这个项 ...

  8. 十七.protobuf在rpc中的使用

    关于protobuf在rpc中的使用,设计到gRPC,相关内容待续....

  9. 这样基于Netty重构RPC框架你不可能知道

    原创申明:本文由公众号[猿灯塔]原创,转载请说明出处标注 今天是猿灯塔“365天原创计划”第5天. 今天呢!灯塔君跟大家讲: 基于Netty重构RPC框架 一.CyclicBarrier方法说明 1. ...

随机推荐

  1. Android在ListView滑动数据混乱

    我相信做过Android应用程序开发或多或少都遇到了这个问题.或者是在ListView数据损坏幻灯片事件.要么GridView数据损坏幻灯片事件. 让我们来看看一个网友写的文章,个人感觉还不错的文章: ...

  2. 金蝶K3管理软件PDA条码解决方式,盘点机与金蝶K3无缝对接

    申明:以上文字为"武汉汉码科技有限公司"原创,转载时务必注明出处. 技术分享,沟通你我,共同进步!www.hanma-scan.com 原帖:http://www.hanma-sc ...

  3. Vivado的helloword计划(一个):硬件project部分

    硬件平台:ZedBoard 软件平台:vivado2013.3 本演示样例通过综合.实现,生成比特流,发送到SDK实现. 启动vivado而且创建一个项目 依据提示操作一步步创建新项目的时候记得选择R ...

  4. 模式识别 - libsvm该函数的调用方法 详细说明

    libsvm该函数的调用方法 详细说明 本文地址: http://blog.csdn.net/caroline_wendy/article/details/26261173 须要载入(load)SVM ...

  5. linux Apache rotatelogs 故障原因及解决方案未生效

    rotatelogs 截断日志.构造.但保存vhost.conf 之后.serverhttpd -k restart 还是无法成功重新启动. 日志文件: (2)No such file or dire ...

  6. R语言做文本挖掘 Part5情感分析

    Part5情感分析 这是本系列的最后一篇文章,该.事实上这种单一文本挖掘的每一个部分进行全部值获取水落石出细致的研究,0基础研究阶段.用R里面现成的算法,来实现自己的需求,当然还參考了众多网友的智慧结 ...

  7. printf交替使用

    今天附带printf一些替代实现. 转载请注明出处:http://blog.csdn.net/u010484477谢谢^_^ 我们总是用printf做各种输出语句: printf("%d&q ...

  8. Android pm命令用法

    Sam综观有关PackageManager时,无意中发现Android 下提供一个pm命令,通常放在/system/bin/下. 这个命令与Package有关.且很有用.所以研究之. 0. Usage ...

  9. mysql 在创建批处理脚本日志表信息

    mysql在批处理脚本通过存储过程如下所示创建日志信息表: drop PROCEDURE if EXISTS reqSp; DELIMITER // create procedure reqSp(sT ...

  10. ASP.NET MVC+EF框架+EasyUI实现权限管理系列(4)-业务逻辑层的封装

    原文:ASP.NET MVC+EF框架+EasyUI实现权限管理系列(4)-业务逻辑层的封装 ASP.NET MVC+EF框架+EasyUI实现权限管系列 (开篇)   (1):框架搭建    (2) ...