耍一把codegen,这样算懂编译么?
最近使用protobuf搭了些服务器,对protobuf的机制略感兴趣,所以研究了下。
大致分析没有什么复杂的
1 对定义的结构体生成消息封包协议
2 对定义的rpc函数生成接口定义
3 用户按protobuf的接口定义实现对应的调用接口
实现上,也颇简单比如如下的一个protobuf文件
// ConnectServerRequest和ConnectServerReply是客户端和服务端建立连接后的第一个RPC请求
// 该请求不包括认证过程,认证过程由Entity去处理,这个只是建立连接,从而启动Entity通信流程
message ConnectServerRequest {
enum RequestType {
NEW_CONNECTION = ; // 新登录
RE_CONNECTION = ; // 断线快速重连
BIND_AVATAR = ; // 重新绑定entity到avatar
}
optional bytes routes = ;
required RequestType type = ; // 认证类型
optional bytes deviceid = ; // 设备 id, 标示客户端,可用mac地址
optional bytes entityid = ; // 断线重连或者BIND_AVATAR的时候需要的avatar entity id
optional bytes authmsg = ; // 验证消息
} // 客户端发给Gate服务器
service IGateService {
// 连接服务器,进行认证
rpc connect_server(ConnectServerRequest) returns (Void);
}
要生成对应的接口文件,消息协议不提,大概就是按一定的顺序在内存中组织下变量的布局,稍复杂的大概就是考虑下大端小端的问题。
在函数的接口上,基本上就是识别到rpc这个关键字,然后提取出函数定义的关键语义比如函数名,参数(类型及实参名),返回值类型。这个过程大概算词法分析?编译上的术语大致如此。
protobuf生成的代码大致如下:
virtual void connect_server(::google::protobuf::RpcController* controller,
const ::mobile::server::ConnectServerRequest* request,
::mobile::server::Void* response,
::google::protobuf::Closure* done); void IGateService_Stub::connect_server(::google::protobuf::RpcController* controller,
const ::mobile::server::ConnectServerRequest* request,
::mobile::server::Void* response,
::google::protobuf::Closure* done) {
channel_->CallMethod(descriptor()->method(),
controller, request, response, done);
} void IGateService::CallMethod(const ::google::protobuf::MethodDescriptor* method,
::google::protobuf::RpcController* controller,
const ::google::protobuf::Message* request,
::google::protobuf::Message* response,
::google::protobuf::Closure* done) {
GOOGLE_DCHECK_EQ(method->service(), IGateService_descriptor_);
switch(method->index()) {
case :
connect_server(controller,
::google::protobuf::down_cast<const ::mobile::server::ConnectServerRequest*>(request),
::google::protobuf::down_cast< ::mobile::server::Void*>(response),
done);
}
}
函数参数是依循protobuf的消息协议生成的结构体,大致上是类似json的k-v结构。
原理分析完,我大概自己写了一个,学protobuf定义了一个rpccall,然后没有定义过于复杂的结构,直接作为一个c++的关键字使用,编译前用我自己写的脚本随便处理下
c++源代码如下:
/*
* acceptservice.h
*
* Created on: 2014-11-3
* Author: qianqians
*/
#ifndef _acceptservice_h
#define _acceptservice_h #include "service.h" namespace Fossilizid{
namespace reduce_rpc{ RPCCALL std::string init(); class acceptservice : public service{
public:
acceptservice(char * ip, short port);
~acceptservice(); private:
RPCCALL std::tuple<int, std::string, float> run_network(int count); RPCCALL std::pair<int, int> run_network(int count, int count1); private:
remote_queue::ENDPOINT ep;
remote_queue::QUEUE que;
remote_queue::ACCEPTOR acp; }; } /* namespace reduce_rpc */
} /* namespace Fossilizid */ #endif //_acceptservice_h
脚本识别到rpccall关键字之后,则提取对应的词法树到一个json串
{'acceptservice.h': {'templateclassfunc': {}, 'classfunc': {'acceptservice': [['std::tuple<int, std::string, float>', 'run_network', 'int count'], ['std::pair<int, int>', 'run_network', 'int count', 'int count1']]}, 'globalfunc': [['std::string', 'init']], 'templateglobalfunc': []}, 'acceptservice.cpp': {'templateclassfunc': {}, 'classfunc': {}, 'globalfunc': [], 'templateglobalfunc': []}}
然后生成对应的客户端代码:
大致就是生成对传入参数的json格式打包以及发送,和等待服务器的响应返回
生成代码如下:
#include <IRemoteEndpoint.h>
std::string init(IRemoteEndpoint ep){
boost::shared_ptr<session> s = GetSession(ep);
Json::Value value;
value['epuuid'] = s.enppui();
value['suuid'] = UUID();
value['eventtype'] = 'rpc_event';
value['rpc_event_type'] = 'call_rpc_mothed';
value['fnargv'] = Json::Value(Json::objectValue) ;
value['fnname'] = 'init';
s->do_push(s, value);
Json::Value ret = _service_handle->wait(value['suuid'].asString(), );
if (ret['suuid'] != value['suuid']){
throw std::exception("error suuid")
}
return ret['rpcret'].asString();
}
class acceptservice{
private:
IRemoteEndpoint ep;
acceptservice(IRemoteEndpoint _ep){
ep = _ep;
}
public:
std::tuple<int, std::string, float> run_network(int count){
boost::shared_ptr<session> s = GetSession(ep);
Json::Value value;
value['epuuid'] = s.enppui();
value['suuid'] = UUID();
value['eventtype'] = 'rpc_event';
value['rpc_event_type'] = 'call_rpc_mothed';
value['fnargv'] = Json::Value(Json::objectValue) ;
value['fnargv']['count'] = count;
value['fnname'] = 'run_network_int';
s->do_push(s, value);
Json::Value ret = _service_handle->wait(value['suuid'].asString(), );
if (ret['suuid'] != value['suuid']){
throw std::exception("error suuid")
}
return std::make_tuple(ret['rpcret'][].asInt(), ret['rpcret'][].asString(), ret['rpcret'][].asFloat());
}
std::pair<int, int> run_network(int count, int count1){
boost::shared_ptr<session> s = GetSession(ep);
Json::Value value;
value['epuuid'] = s.enppui();
value['suuid'] = UUID();
value['eventtype'] = 'rpc_event';
value['rpc_event_type'] = 'call_rpc_mothed';
value['fnargv'] = Json::Value(Json::objectValue) ;
value['fnargv']['count'] = count;
value['fnargv']['count1'] = count1;
value['fnname'] = 'run_network_int_int';
s->do_push(s, value);
Json::Value ret = _service_handle->wait(value['suuid'].asString(), );
if (ret['suuid'] != value['suuid']){
throw std::exception("error suuid")
}
return std::make_pair(ret['rpcret'][ret0].asInt(), ret['rpcret'][ret1].asInt());
}
};
看起来,还算好看,以上!
耍一把codegen,这样算懂编译么?的更多相关文章
- JAVA虚拟机学习笔记(一)Windows10下编译OpenJDK8
转载请注明源地址:http://www.cnblogs.com/lighten/p/5906359.html 1. 编译环境的准备 1.1 JDK源码下载 OpenJDK是JAVA发展史中的一个开源项 ...
- VS编译的QT程序发布时产生的AppCrash问题
至少我碰到了三个情况,都是AppCrash错误(以下都指VS2008的Release的设置) 第1个错误,报错模块是程序自己 我使用VS2008 Team with SP1和QT4.86编译程序,一直 ...
- Fedora20 编译安装qemu-system
安装简介: 1.1. 本次编译安装所有的操作都在Fedora 20 x86-64上,内核版本为: 3.14.4-200.fc20.x86_64.如果在其他系统编译安装,请看其他文章. 2.安装准备: ...
- 编译filezilla
编译zilla的时候,需要用到与mysql连接的地方(这里先忽略zila的编译) VC听过mysql connector c++, 下载了1.1.3版本,然后飞安装包,之后从官网上下载boost 把库 ...
- 一生伏首拜阳明------<明朝那些事儿>
一生伏首拜阳明. 王守仁,字伯安,别号阳明. 成化八年(1472),王守仁出生在浙江余姚,大凡成大事者往往出身贫寒,小小年纪就要上山砍柴,下海捞鱼,家里还有几个生病的亲属,每日以泪洗面.这差不多也是惯 ...
- 不要困在自己建造的盒子里——写给.NET程序员(附精彩评论)
此文章的主旨是希望过于专注.NET程序员在做好工作.写好.NET程序的同时,能分拨出一点时间接触一下.NET之外的东西(例如10%-20%的时间),而不是鼓动大家什么都去学最后什么都学不精,更不是说. ...
- 一些对数学领域及数学研究的个人看法(转载自博士论坛wcboy)
转自:http://www.math.org.cn/forum.php?mod=viewthread&tid=14819&extra=&page=1 原作者: wcboy 现在 ...
- Python伪开发者对于搜狐云景的测评
Python伪开发者对于搜狐云景的测评 本人是GAE和OpenShift的狂热爱好者,玩过各种国外PaaS.某次想搞个稍微复杂点的Python Web程序,需要比较好的网络传输速度,就试图找前PM(P ...
- 本科非cs菜鸟计算机面试实录
两年制小硕,本硕期间差不多都打酱油的.本科非cs专业,硕士cs,编程基础一般,专业基础尚可.研究生期间分析分析了pgsql数据库的源码:同时实验室一些杂项目:自己业余为了应试读了些计算机书.自己当时q ...
随机推荐
- hdu1312 Red and Black 简单BFS
简单BFS模版题 不多说了..... 直接晒代码哦.... #include<cstdlib> #include<iostream> #include<cstdio> ...
- weblogic java.lang.OutOfMemoryError: PermGen space 问题解决方法
文章转自:http://blog.csdn.net/cuihaiyang/article/details/6679735 最近安装了WebLogic10.3.4,测试在weblogic上部署项目,没过 ...
- LeetCode:1. Add Two Numbers
题目: LeetCode:1. Add Two Numbers 描述: Given an array of integers, return indices of the two numbers su ...
- JAVA虚拟机系列文章
本系列文章主要记录自己在学习<深入理解Java虚拟机-JVM高级特性与最佳实践>的知识点总结,文章内容都是基于周志明所著书籍的总结. 1.Java内存区域与溢出 2.垃圾收集器与内存分配策 ...
- C#单元测试,带你入门
注:本文示例环境 VS2017 XUnit 2.2.0 单元测试框架 xunit.runner.visualstudio 2.2.0 测试运行工具 Moq 4.7.10 模拟框架 为什么要编写单元测试 ...
- 机器学习:Python实现聚类算法(一)之K-Means
1.简介 K-means算法是最为经典的基于划分的聚类方法,是十大经典数据挖掘算法之一.K-means算法的基本思想是:以空间中k个点为中心进行聚类,对最靠近他们的对象归类.通过迭代的方法,逐次更新各 ...
- CCS Debug Assertion Failed
下载安装CCS7.1后编译工程时报错,如下: 本来以为这种情况是由于CCS没有安装成功所导致的,但尝试安装其他版本时也发生同样的问题. 于是登录到 TI的wiki 上查找原因,在安装栏下说明: Ens ...
- 今天重装系统后,Wdows更新提示“windows update当前无法检查更新,因为未运行服务。您可能需要重新启动计算机”
到百度搜了常用的解决方法,就是用命令提示符,但对我的情况不管用,提示“拒绝访问”.后来在08绿软站的一篇文章中找到了解决办法.原文如下(我本人也是用的第四种方法解决的): 试了下面几种解决方法,第四种 ...
- 点评阿里JAVA手册之异常日志(异常处理 日志规约 )
下载原版阿里JAVA开发手册 [阿里巴巴Java开发手册v1.2.0] 本文主要是对照阿里开发手册,注释自己在工作中运用情况. 本文内容:异常处理 日志规约 本文难度系数为一星(★) 本文为第三篇 ...
- ReactNative学习之Html基本标签使用
前言: 前面简单学习了html简单标签的使用,今天学习一下其他的标签的使用. HTML的超链接 1.)创建一个超链接 <div> <p> <a href="ht ...