可以比较使用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. UVA 847 - A Multiplication Game(游戏)

    UVA 847 - A Multiplication Game 题目链接 题意:一个数一開始是1,每次轮流乘2-9,谁先大于n谁就赢,问谁胜 思路:博弈,找出必胜态.2-9为stan,10-18为ol ...

  2. LINQ之路(2):LINQ to SQL本质

    LINQ之路(2):LINQ to SQL本质 在前面一篇文章中回顾了LINQ基本语法规则,在本文将介绍LINQ to SQL的本质.LINQ to SQL是microsoft针对SQL Server ...

  3. LVM pvcreate,vgcreate,lvcreate,mkfs

    首先介绍LVM的几个概念:     1. 物理卷Physical volume (PV):可以在上面建立卷组的媒介,可以是硬盘分区,也可以是硬盘本身或者回环文件(loopback file).物理卷包 ...

  4. mysql经常使用命令总结

    MySQL经常使用指令(备查) 最经常使用的显示命令: 1.显示数据库列表.  show databases;  2.显示库中的数据表:  use mysql; show tables;  3.显示数 ...

  5. SQL Server安全性专题一:简介

    原文:SQL Server安全性专题一:简介 一. 安全威胁与法则 1. 安全定义 2. 安全威胁 3. 安全法则 安全定义: 在SQLServer环境中,安全性可以认为是[数据保护].包括:  数 ...

  6. UVA 10529 Dumb Bones 可能性dp 需求预期

    主题链接:点击打开链接 题意: 要在一条直线上摆多米诺骨牌. 输入n, l, r 要摆n张排,每次摆下去向左倒的概率是l, 向右倒的概率是r 能够採取最优策略.即能够中间放一段.然后左右两边放一段等, ...

  7. (大数据工程师学习路径)第四步 SQL基础课程----约束

    一.简介 约束是一种限制,它通过对表的行或列的数据做出限制,来确保表的数据的完整性.唯一性.本节实验就在操作中熟悉MySQL中的几种约束. 二.内容 1.约束分类 听名字就知道,约束是一种限制,它通过 ...

  8. Online网站集

    http://tool.oschina.net/apidocs/    在线工具(IT技术工具)

  9. 客房收费系统改造(三)—厂+反射+DAL

    前一段时间有一个简单的三登录功能实现窗口,心灵修养一点点,但很快就被泼了一盆冷水.房费是不可能做到在短短三年,假设你使用三个,这倒房费三个功能必须使用函数来实现.了七层的研究. 经过一个星期的看博客. ...

  10. 5、VS2010+ASP.NET MVC4+EF4+JqueryEasyUI+Oracle该项目的开发——使用datagrid做报表

    来点需要:我使用的数据库访问EF框架,但是,因为使用一个动态表来的统计报告中.单独是每天产生基于数据表,它是很难使用EF加盟前.所以我包装在两组数据库存取层的框内,一个是EF,一种是传统的ADO.NE ...