RPC中文叫远程函数调用,它是一种通信方式,只是看起来像普通的函数调用。

它包括三个基本要素:

1:服务端注册相应的(服务)函数(用于调用方调用)

2:调用方通过函数调用的方式将一些信息和参数打包到消息,然后发送消息给被调用方。

3:被调用方收到消息后,提取信息和参数。调用相应函数。

被调用方不需要用户手动解析参数,而是由"包装代码"预先解析出来。

目前很多rpc框架都(设计)配有协议描述文件,通过代码生成,产生((含有)"包装代码")服务端的服务类或函数。

我不喜欢代码生成,我喜欢直接在代码中搞定它。

果然,我最近看到有朋友在一些脚本语言中做到这点。某些实现还不需要手动(预先)注册服务函数。

比如:

https://github.com/sniperHW/distri.lua/blob/master/examples/rpcserver.lua

https://github.com/akirayu101/GM_RPC/blob/master/gmrpc_lua/rpc_handlers/rpc_handler_sample.lua

https://github.com/akirayu101/GM_RPC/blob/master/gmrpc_py/rpc_handlers/rpc_handler_sample.py

然而我又不熟悉lua或python,所以我用C++11 来实现了它。

主要功能:

1:注册服务函数

  1. void test5(string a, int b, map<int, map<int, string>> vlist)
  2. {
  3. }
  4.  
  5. rpc rpc_server; /*rpc服务器*/
  6. rpc_server.def("test5", test5);

2:客户端调用远程函数

  1. rpc rpc_client; /*rpc客户端*/
  2. rpc_client.call("test5", "a", 1, mlist, [&upvalue](int a, int b){
  3. upvalue++;
  4. cout << "upvalue:" << upvalue << ", a:" << a << ", b:" << b << endl;
  5. });

其中mlis是一个map<int,map<int,string>>类型变量。 rpc_client.call 的返回值是一个string,它表示此次call的消息。

我们可以把它(string 消息)通过网络发送给服务器。在这里(测试)我们直接通过下面的方式传递给服务端。

!!!注意!!!:call的最后一个参数可以是一个lambda,它表示处理此rpc返回值。 如果不是一个lambda,则它也是rpc调用参数。

3:服务端处理rpc request

  1. rpc_server.handleRpc(rpc_request_msg);

其中 rpc_request_msg为接受到的网络消息(字符串)。

这样就会自动调用到我们的 test5 函数。 并且形参已经(自动)准备OK。你只需要在test5 里使用这些参数即可。(不用关心网络消息协议)。

4:被调用方可以返回数据给调用方

  1. rpc_response_str = rpc_server.reply(1, 1, 2); /* (1,1,2)中的1为调用方的req_id, (1,2)为返回值 */
  2. rpc_client.handleResponse(rpc_response_str);

上面代码通过 rpc_server.reply返回消息给客户端。 然后客户端模拟收到消息后通过 rpc_client.handleResponse(rpc_response_str)

会回调rpc_client.call() 时 所传递的lambda回调函数。

注意:以上 服务函数(譬如test5)和rpc 返回值处理函数(譬如那个lambda)的参数 是任意个数,且"任意"类型

(支持 int,string,JsonObject-json对象,vector<int>,vector<string>, map<int,string>,map<string,int>,map<string,string>, map<int/string, 前述所有类型/递归> )

整个测试代码:

  1. void test1(int a, int b)
  2. {
  3. cout << "in test1" << endl;
  4. cout << a << ", " << b << endl;
  5. }
  6.  
  7. void test2(int a, int b, string c)
  8. {
  9. cout << "in test2" << endl;
  10. cout << a << ", " << b << ", " << c << endl;
  11. }
  12.  
  13. void test3(string a, int b, string c)
  14. {
  15. cout << "in test3" << endl;
  16. cout << a << ", " << b << ", " << c << endl;
  17. }
  18.  
  19. void test4(string a, int b)
  20. {
  21. cout << "in test4" << endl;
  22. cout << a << "," << b << endl;
  23. }
  24.  
  25. void test5(string a, int b, map<int, map<int, string>> vlist)
  26. {
  27. }
  28.  
  29. void test6(string a, int b, map<string, int> vlist)
  30. {
  31. }
  32.  
  33. void test7()
  34. {
  35. cout << "in test7" << endl;
  36. }
  37.  
  38. int main()
  39. {
  40. int upvalue = 10;
  41. using namespace dodo;
  42.  
  43. rpc rpc_server; /*rpc服务器*/
  44. rpc rpc_client; /*rpc客户端*/
  45.  
  46. rpc_server.def("test4", test4);
  47. rpc_server.def("test5", test5);
  48. rpc_server.def("test7", test7);
  49.  
  50. string rpc_request_msg; /* rpc消息 */
  51. string rpc_response_str; /* rpc返回值 */
  52.  
  53. {
  54. rpc_request_msg = rpc_client.call("test7");
  55.  
  56. rpc_server.handleRpc(rpc_request_msg);
  57. }
  58.  
  59. map<int, string> m1;
  60. m1[1] = "Li";
  61. map<int, string> m2;
  62. m2[2] = "Deng";
  63. map<int, map<int, string>> mlist;
  64. mlist[100] = m1;
  65. mlist[200] = m2;
  66.  
  67. {
  68. rpc_request_msg = rpc_client.call("test5", "a", 1, mlist, [&upvalue](int a, int b){
  69. upvalue++;
  70. cout << "upvalue:" << upvalue << ", a:" << a << ", b:" << b << endl;
  71. });
  72.  
  73. rpc_server.handleRpc(rpc_request_msg);
  74. }
  75.  
  76. {
  77. rpc_request_msg = rpc_client.call("test5", "a", 1, mlist, [&upvalue](string a, string b, int c){
  78. upvalue++;
  79. cout << "upvalue:" << upvalue << ", a:" << a << ", b:" << b << ", c:" << c << endl;
  80. });
  81.  
  82. rpc_server.handleRpc(rpc_request_msg);
  83. }
  84.  
  85. {
  86. rpc_request_msg = rpc_client.call("test4", "a", 1);
  87. rpc_server.handleRpc(rpc_request_msg);
  88. }
  89.  
  90. /* 模拟服务器通过reply返回数据给rpc client,然后rpc client处理收到的rpc返回值 */
  91. {
  92. rpc_response_str = rpc_server.reply(1, 1, 2); /* (1,1,2)中的1为调用方的req_id, (1,2)为返回值 */
  93. rpc_client.handleResponse(rpc_response_str);
  94. }
  95.  
  96. {
  97. rpc_response_str = rpc_server.reply(2, "hello", "world", 3);
  98. rpc_client.handleResponse(rpc_response_str);
  99. }
  100.  
  101. cin.get();
  102. return 0;
  103. }

RPC"框架"代码地址: https://github.com/IronsDu/accumulation-dev/blob/master/utils/rpc_test.cpp 。

欢迎讨论。

---update:

我们来看看最新战果:

  1. class Player : public dodo::rpc
  2. {
  3. public:
  4. Player()
  5. {
  6. registerHandle("player_attack", &Player::attack);
  7. registerHandle("player_hi", &Player::hi);
  8. }
  9.  
  10. private:
  11. template<typename... Args>
  12. void registerHandle(string name, void (Player::*callback)(Args...))
  13. {
  14. def(name.c_str(), [this, callback](Args... args){
  15. (this->*callback)(args...);
  16. });
  17. }
  18.  
  19. private:
  20. void attack(string target)
  21. {
  22. cout << "attack:" << target << endl;
  23. }
  24.  
  25. void hi(string i, string j)
  26. {
  27. cout << i << j << endl;
  28. }
  29. };
  30.  
  31. Player rpc_server; /*rpc服务器*/
  32. Player rpc_client; /*rpc客户端*/
  33.  
  34. rpc_request_msg = rpc_client.call("player_attack", "Li Lei");
  35. rpc_server.handleRpc(rpc_request_msg);
  36. rpc_request_msg = rpc_client.call("player_hi", "Hello", "World");
  37. rpc_server.handleRpc(rpc_request_msg);
 是不是非常简单呢?很轻松的把消息(参数)自动派发到实际的业务函数里?

每一个Player就是一个rpc,再结合网络库,就能很轻松的开发业务逻辑。

智能 RPC框架 (C++)的更多相关文章

  1. rpc框架之 thrift 学习 1 - 安装 及 hello world

    thrift是一个facebook开源的高效RPC框架,其主要特点是跨语言及二进制高效传输(当然,除了二进制,也支持json等常用序列化机制),官网地址:http://thrift.apache.or ...

  2. RPC框架实践之:Apache Thrift

    一.概述 RPC(Remote Procedure Call)即 远程过程调用,说的这么抽象,其实简化理解就是一个节点如何请求另一节点所提供的服务.在文章 微服务调用链追踪中心搭建 一文中模拟出来的调 ...

  3. SpringCloud Alibaba (四):Dubbo RPC框架

    Dubbo简介 Apache Dubbo |ˈdʌbəʊ| 是一款高性能.轻量级的开源Java RPC框架,它提供了三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现.致 ...

  4. RPC 框架 Dubbo 从理解到使用(一)

    技术架构演变 单一应用架构 通俗地讲,"单体应用(monolith application)"就是将应用程序的所有功能都打包成一个独立的单元.当网站流量很小时,只需一个应用,将所有 ...

  5. 什么是RPC,RPC好处,常用的RPC框架

    RPC简介 RPC(Remote Procedure Call Protocol)远程过程调用协议.一个通俗的描述是:客户端在不知道调用细节的情况下,调用存在于远程计算机上的某个对象,就像调用本地应用 ...

  6. 【万字长文】Dubbo 入门总结 ,一款高性能的 Java RPC 框架

    这篇文章是我学习整理 Dubbo 的一篇文章,首先大部分内容参考了官网 + 某硅谷的视频,内容讲解进行了重新编排,40多张图片,也都是我修改重制的,虽然一万多字,但是其实也可以看出来,更多的内容集中在 ...

  7. RPC框架实现 - 通信协议篇

    RPC(Remote Procedure Call,远程过程调用)框架是分布式服务的基石,实现RPC框架需要考虑方方面面.其对业务隐藏了底层通信过程(TCP/UDP.打包/解包.序列化/反序列化),使 ...

  8. 微博轻量级RPC框架Motan

    Motan 是微博技术团队研发的基于 Java 的轻量级 RPC 框架,已在微博内部大规模应用多年,每天稳定支撑微博上亿次的内部调用.Motan 基于微博的高并发和高负载场景优化,成为一套简单.易用. ...

  9. 一个轻量级分布式RPC框架--NettyRpc

    1.背景 最近在搜索Netty和Zookeeper方面的文章时,看到了这篇文章<轻量级分布式 RPC 框架>,作者用Zookeeper.Netty和Spring写了一个轻量级的分布式RPC ...

随机推荐

  1. jquery 回车切换 tab功能

    挺有趣的,Jquery 回车切换tab功能的实现哦 <html> <head><!--jquery库.js--></head> <body> ...

  2. HDU 1847 Good Luck in CET-4 Everybody!(找规律,或者简单SG函数)

    Good Luck in CET-4 Everybody! Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K ...

  3. oracle根据正则表达式查找对应的字段

    语法如下: SELECT * FROM 表名WHERE regexp_like(表字段,'正则') 例如: 查找某字段小数点后有两个小数以上的信息 SELECT * FROM A TWHERE reg ...

  4. C# JackLib系列之GdiHelper圆角矩形的快速生成

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.D ...

  5. 关于JPA封装数据库数据到实体不调用属性的get和set的方法解决办法

    今天发现JPA封装数据库数据到实体并不调用属性的get和set的,郁闷,本来想在set方法做改字段的值处理的谁知道遇到这个情况: @Column(name = acode) @Access(value ...

  6. c#学习之旅------01

    一.交换两个数的值 //交换两个数的值 #region 方法一 , num2 = ;//待交换的两个数值 int temp;//临时变量 temp = num1; num1 = num2; num2 ...

  7. 使用spring.net 1.3.2框架部署在虚拟目录上发生错误

    如果你的网站使用了Spring.net 1.3.2,并部署在IIS的虚拟目录上,那么将会出现如下错误:    The virtual path '/currentcontext.dummy' maps ...

  8. CentOS FireFox Flash Player

    yum install *firefox* yum install flash-plugin

  9. PHP安装环境,服务器不支持curl_exec的解决办法

    转自:http://jingyan.baidu.com/article/00a07f38909c6b82d028dc83.html windows下开启方法: 拷贝PHP目录中的libeay32.dl ...

  10. PHPCMS教程

    第一章 模版 参见:http://blog.163.com/zh_astro/blog/static/1842084562011430430419/ 碎片管理: 在模版页面需要添加碎片的位置加上代码{ ...