背景

myrpc是基于protobuf开发的远程调用框架,对于rpc服务,在proto文件中的定义如下:

   经过protoc编译后,会生成两个类:UserServiceRpc 和 UserServiceRpc_Stub,在之前的文章中已经分析过,UserServiceRpc_Stub类是继承于UserServiceRpc,两者均继承于protobuf中是service这个基类,其中UserServiceRpc_Stub是供rpc访问的消费者(调用方)使用。

   可以发现,在UserServiceRpc_Stub类中的所有方法其底层都是调用RpcChannel::CallMethod()方法,我们再来看一下CallMethod()方法中到底实现了什么逻辑,代码如下:

   RpcChannel是一个抽象类,需要我们在框架中实现:

//提供给框架的调用方使用
class MyrpcChannel : public google::protobuf::RpcChannel
{public://所有提供stub代理对象调用的rpc方法,都走到这里,统一做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);
};

其中CallMethod的实现是关键,所有提供stub代理对象调用的rpc方法,都要使用该方法,来做rpc方法调用的数据序列化和网络发送。具体的过程放在下面说,先梳理调用方需要做哪些操作。

  1. 整个程序启动后,想要使用myrpc框架来享受rpc服务调用,一定需要先调用框架的初始化函数:
      MyrpcApplication::init(argc,argv);
  1. 创建xxx_stub对象
      taoye::UserServiceRpc_Stub stub(new MyrpcChannel());
  1. 填充请求message
    //rpc方法的请求参数taoye::LoginRequest request;request.set_name("zhang san");request.set_pwd("123456");
  1. 定义响应消息的message
    //rpc方法的响应taoye::LoginResponse response;
  1. 发起rpc方法的调用
    stub.login(&controller,&request,&response,nullptr);   //底层调用的是RpcChanel::CallMethod方法,即MyrpcChannel::callmethod

最后我们再来看一下,我们定义的继承于RpcChannel的MyrpcChannel中CallMethod方法中实现了哪些逻辑,主要分为两个,一是请求数据的序列化,二是将序列化后的数据提供网络发送出去。

  • 数据的序列化:要根据事先约定好的格式来组装数据
//数据的发送格式:header_size  +  service_name method_name args_size  +  argsconst google::protobuf::ServiceDescriptor* sd = method->service();std::string service_name = sd->name();   //service_namestd::string method_name = method->name();  //method_name//获取参数的序列化字符串的长度 args_sizeuint32_t args_size=0;std::string args_str;if(request->SerializeToString(&args_str)){args_size=args_str.size();}else{// std::cout<<"serialize request error!"<<std::endl;controller->SetFailed("serialize request error!");return ;}// 定义rpc的请求header  在框架中的proto文件中事先约定好请求格式myrpc::RpcHeader rpcHeader;rpcHeader.set_service_name(service_name);rpcHeader.set_method_name(method_name);rpcHeader.set_args_size(args_size);uint32_t header_size=0;std::string rpc_header_str;if(rpcHeader.SerializeToString(&rpc_header_str)){header_size = rpc_header_str.size();   //获取头的长度}else{//std::cout<<"serialize rpc header error!"<<std::endl;controller->SetFailed("serialize rpc header error!");return ;}//组织待发送的rpc请求的字符串std::string send_rpc_str;send_rpc_str.insert(0,std::string((char*)&header_size,4)); //注意,要将header_size的值以二进制的形式填入发送字符串中send_rpc_str+=rpc_header_str;send_rpc_str+=args_str;
  • 使用TCP编程,完成数据的发送,实现rpc方法的远程调用。
       要先创建套接字
       再根据想要调用的service_name和method_name在zookeeper上查询该服务所 ;在的ip和port
       发起连接,连接到rpc服务节点
       接受rpc请求的响应值
       将响应值反序列化
    //创建套接字int clientfd = socket(AF_INET, SOCK_STREAM, 0);if(-1 == clientfd){//std::cout<<"create socket error! errno: "<<errno<<std::endl;char errtxt[512] ={0};sprintf(errtxt,"create socket error! errno:%d ",errno);controller->SetFailed(errtxt);return ;}/*// 读取配置文件rpcservice的信息std::string ip=MyrpcApplication::GetInstance().GetConfig().Load("rpcserverip");uint16_t port = atoi(MyrpcApplication::GetInstance().GetConfig().Load("rpcserverport").c_str());*///根据service_name 和method_name 在zk上查询   从而得到ip和portZkClient zkCli;zkCli.Start();//  /UserServiceRpc/Loginstd::string method_path = "/" + service_name + "/" + method_name;// 127.0.0.1:8001std::string host_data = zkCli.GetData(method_path.c_str());if (host_data == ""){controller->SetFailed(method_path + " is not exist!");return;}int idx = host_data.find(":");if (idx == -1){controller->SetFailed(method_path + " address is invalid!");return;}std::string ip = host_data.substr(0, idx);uint16_t port = atoi(host_data.substr(idx+1, host_data.size()-idx).c_str()); struct sockaddr_in server_addr;server_addr.sin_family = AF_INET;server_addr.sin_port = htons(port);server_addr.sin_addr.s_addr=inet_addr(ip.c_str());//发起连接,连接rpc服务节点if(-1==connect(clientfd,(struct sockaddr*)&server_addr,sizeof(server_addr))){//std::cout<<"connect error! errno: "<<errno<<std::endl;char errtxt[512] ={0};sprintf(errtxt,"connect error! errno:%d ",errno);controller->SetFailed(errtxt);close(clientfd);exit(EXIT_FAILURE);}//发送rpc请求if(-1==send(clientfd,send_rpc_str.c_str(),send_rpc_str.size(),0)){//std::cout<<"send error! errno: "<<errno<<std::endl;char errtxt[512] ={0};sprintf(errtxt,"send error! errno:%d ",errno);controller->SetFailed(errtxt);close(clientfd);return ;}//接收rpc请求的响应值char recv_buf[1024] = {0};int recv_size=0;if(-1 == (recv_size=recv(clientfd,recv_buf,1024,0))){//std::cout<<"recv error! errno: "<<errno<<std::endl;char errtxt[512] ={0};sprintf(errtxt,"recv error! errno:%d ",errno);controller->SetFailed(errtxt);close(clientfd);return ;}// 反序列化rpc调用的响应数据// std::string response_str(recv_buf,0,recv_size);// if(!response->ParseFromString(response_str))if(!response->ParseFromArray(recv_buf,recv_size)){//std::cout<<"parse error! response_str: "<< recv_buf<<std::endl;char errtxt[512] ={0};sprintf(errtxt,"parse error! response_str:%s ",recv_buf);controller->SetFailed(errtxt);close(clientfd);return ;}close(clientfd);

RPC 框架梳理——RPC使用方的调用流程梳理相关推荐

  1. 【RPC框架、RPC框架必会的基本知识、手写一个RPC框架案例、优秀的RPC框架Dubbo、Dubbo和SpringCloud框架比较】

    一.RPC框架必会的基本知识 1.1 什么是RPC? RPC(Remote Procedure Call --远程过程调用),它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络的技术. ...

  2. 从零实现RPC框架1:RPC框架架构设计

    从零实现RPC框架1:RPC框架架构设计 1.什么是 RPC? RPC 的全称是 Remote Procedure Call,即远程过程调用.简单解读字面上的意思,远程肯定是指要跨机器而非本机,所以需 ...

  3. 支撑微博千亿调用的轻量级RPC框架:Motan

    随着微博容器化部署以及混合云平台的高速发展,RPC 在微服务化的进程中越来越重要,对 RPC 的需求也产生了一些变化.今天主要介绍一下微博 RPC 框架 Motan,以及为了更好的适应混合云部署所做的 ...

  4. 远程过程调用RPC 2:RPC思想与RPC框架

    RPC思想与RPC框架 RPC思想 组成部分 RPC框架 完整的RPC框架 RPC调用关键点 RPC框架分类对比 RPC和REST REST主要原则 对比 RPC思想 上一篇笔记:远程过程调用RPC ...

  5. 如何手撸一个较为完整的RPC框架

    [文章作者/来源]一个没有追求的技术人/https://sourl.cn/sJ4Brp 缘 起 最近在公司分享了手撸RPC,因此做一个总结. 概 念 篇 RPC 是什么? RPC 称远程过程调用(Re ...

  6. 什么是RPC?RPC框架dubbo的核心流程

    一.REST 与 RPC: 1.什么是 REST 和 RPC 协议: 在单体应用中,各模块间的调用是通过编程语言级别的方法函数来实现,但分布式系统运行在多台机器上,一般来说,每个服务实例都是一个进程, ...

  7. 经典项目|手撸一个高质量RPC框架

    hi, 大家好,RPC是后端系统节点之间通信的核心技术,属于后端开发必须要学习的技能. 后端技术趋势指南|如何选择自己的技术方向 如何从0搭建公司的后端技术栈 远程过程调用(Remote Proced ...

  8. 如何手撸一个较为完整的RPC框架?

    点击关注公众号,实用技术文章及时了解 来源:juejin.cn/post/6992867064952127524 缘起 最近在公司分享了手撸RPC,因此做一个总结. 概念篇 RPC 是什么? RPC ...

  9. 走进Dubbo——RPC框架简介

    前言 dubbo是阿里开源的分布式rpc框架,在许多中小企业的微服务化过程中发挥着核心作用.但是想把dubbo运行起来也不是那么简单的,这几天我想搭个dubbo环境玩玩,一路受阻. 相信前来了解rpc ...

最新文章

  1. 刷题:递归问题与动态规划
  2. Exchange Server 2010中控制台用命令设置用户邮箱自动回复
  3. kafka源码分析之一server启动分析
  4. defined 函数使用
  5. 【Homework】什么是多态,多态具体体现有哪些?
  6. stl reserve_vector :: reserve()函数以及C ++ STL中的示例
  7. 抗锯齿 文字_PS之使用文字工具
  8. 作为现代计算机理论的基础的,作为现代计算机理论基础的冯·诺依曼原理和思想是()。...
  9. c语言程序100例第5题
  10. 视频分享:做“有料”的计算机大学生
  11. s3c2440的pwm输出
  12. 基于ssm公租房管理系统
  13. 十天学会单片机和c语言编程,十天学会单片机和C语言编程
  14. 苹果电脑如何改id?这篇文章帮你搞定
  15. 青龙羊毛---小龙传奇
  16. 九鼎无双一面面经【凉】
  17. ArcGIS Pro试用申请
  18. (三)CSS前端开发面试会问到的问题有哪些?
  19. C# 之 Math取整数
  20. 2022年现场综合化维护工程师四级认证考试题目

热门文章

  1. MyBatis查询结果resultType
  2. nodejs+vue+elementui游戏新闻资讯网站管理系统
  3. 积分管理系统项目小结
  4. vue一键截图并上传至后台
  5. 如何一天制作100个原创短视频?
  6. KOA框架编程18-多文件上传-③-el-upload插件上
  7. 两个pdf文档怎么合并在一起
  8. java调用ocx控件获取数据_Java调用ocx控件以及dll
  9. chrome应用商店打不开,怎么下载vue-devtools并安装呢?
  10. 微信小程序之消息模板推送