用C代码简要模拟实现一下RPC(远程过程调用)并谈谈它在代码调测中的重要应用【转】
转自:http://blog.csdn.net/stpeace/article/details/44947925
版权声明:本文为博主原创文章,转载时请务必注明本文地址, 禁止用于任何商业用途, 否则会用法律维权。 http://blog.csdn.net/stpeace/article/details/44947925
说明: 本文仅仅是一种模拟的RPC实现, 真正的RPC实现还是稍微有点复杂的。
我们来看看下面这个常见的场景: 在某系统中,我们要对某一函数进行调测, 但是, 很难很难构造出这个函数被调用的实际场景, 怎么办?
虽然很难构造出这个函数被调用的实际场景, 但我们完全可以在代码中主动调用这个函数啊。多想方法(直接方法和间接方法),
少找借口, 并且坚信方法总是存在的。我们可以搞一个触发的操作, 每触发一次, 就调用到该系统中的该函数。 可是, 如果这个系统比较封闭,
比如是某嵌入式系统, 也不好触发。 没关系, 我们借用RPC的思路来实现: 让这个系统做服务端, 然后在客户端上触发。
什么是RPC(远程过程调用)呢?度娘介绍了很多, 我不想搞那么复杂, 所以用一句白话来解释RPC:
进程A向进程B发送消息, 触发进程B的函数被执行,这样, 从形式上看, 好像就是进程A远程调用了进程B的函数, 这就是所谓的RPC(实际上,
进程A仅仅是触发而已, 真正执行的仍然是进程B, 但理解为进程A远程调用了进程B的函数, 也是很爽的)
下面, 基于上面介绍的代码调测场景, 我来简要实现一下RPC:
服务端程序为(进程B):
- #include <stdio.h>
- #include <winsock2.h> // winsock接口
- #pragma comment(lib, "ws2_32.lib") // winsock实现
- SOCKET sockConn; // 全局的通信socket
- // RPC函数(Remote Procedure Calling)
- void readIP()
- {
- printf("ip is 192.168.1.100\n");
- }
- // RPC函数(Remote Procedure Calling)
- void readMask()
- {
- printf("mask is 255.255.255.0\n");
- }
- // RPC函数(Remote Procedure Calling)
- void readGateway()
- {
- printf("gateway is 192.168.1.1\n");
- }
- // 消息处理线程
- DWORD WINAPI handleThread(LPVOID pM)
- {
- while(1)
- {
- char szMsg[100] = {0};
- int nRet = recv(sockConn, szMsg, sizeof(szMsg) - 1, 0);
- if(nRet <= 0)
- {
- printf("recv error\n");
- closesocket(sockConn);
- break;
- }
- // 仅仅考虑读操作, 预期的形式为: read xxx
- char szOperType[20] = {0};
- char szParaName[50] = {0};
- nRet = sscanf(szMsg, "%s %s", szOperType, szParaName);
- if(2 != nRet)
- {
- printf("command error\n");
- continue;
- }
- if(0 != strcmp(szOperType, "read"))
- {
- printf("type error\n");
- continue;
- }
- // 其实, 下面的部分最好用C++ STL的map来做, 为了简便示意, 我就没用map搞了
- if(0 == strcmp(szParaName, "ip"))
- {
- readIP();
- }
- else if(0 == strcmp(szParaName, "mask"))
- {
- readMask();
- }
- else if(0 == strcmp(szParaName, "gateway"))
- {
- readGateway();
- }
- else
- {
- printf("parameter error\n");
- continue;
- }
- Sleep(200);
- }
- return 0;
- }
- int main()
- {
- WORD wVersionRequested; // 双字节,winsock库的版本
- WSADATA wsaData; // winsock库版本的相关信息
- wVersionRequested = MAKEWORD(1, 1); // 0x0101 即:257
- // 加载winsock库并确定winsock版本,系统会把数据填入wsaData中
- WSAStartup( wVersionRequested, &wsaData );
- // AF_INET 表示采用TCP/IP协议族
- // SOCK_STREAM 表示采用TCP协议
- // 0是通常的默认情况
- unsigned int sockSrv = socket(AF_INET, SOCK_STREAM, 0);
- SOCKADDR_IN addrSrv;
- addrSrv.sin_family = AF_INET; // TCP/IP协议族
- addrSrv.sin_addr.S_un.S_addr = inet_addr("0.0.0.0"); // socket对应的IP地址
- addrSrv.sin_port = htons(8888); // socket对应的端口
- // 将socket绑定到某个IP和端口(IP标识主机,端口标识通信进程)
- bind(sockSrv,(SOCKADDR*)&addrSrv, sizeof(SOCKADDR));
- // 将socket设置为监听模式,5表示等待连接队列的最大长度
- listen(sockSrv, 5);
- // sockSrv为监听状态下的socket
- // &addrClient是缓冲区地址,保存了客户端的IP和端口等信息
- // len是包含地址信息的长度
- // 如果客户端没有启动,那么程序一直停留在该函数处
- SOCKADDR_IN addrClient;
- int len = sizeof(SOCKADDR);
- sockConn = accept(sockSrv,(SOCKADDR*)&addrClient, &len);
- // 开启消息处理线程
- HANDLE handle = CreateThread(NULL, 0, handleThread, NULL, 0, NULL);
- while(1); // 卡住, 表示主线程去做自己的事情, 忙自己的东西
- CloseHandle(handle);
- closesocket(sockConn);
- closesocket(sockSrv);
- WSACleanup();
- return 0;
- }
启动服务端。
然后看看客户端(进程A):
- #include <winsock2.h>
- #include <stdio.h>
- #pragma comment(lib, "ws2_32.lib")
- int main()
- {
- WORD wVersionRequested;
- WSADATA wsaData;
- wVersionRequested = MAKEWORD(1, 1);
- SOCKET sockClient = 0;
- WSAStartup( wVersionRequested, &wsaData );
- sockClient = socket(AF_INET, SOCK_STREAM, 0);
- SOCKADDR_IN addrSrv;
- addrSrv.sin_addr.S_un.S_addr = inet_addr("192.168.1.100"); // 请替换为合适的ip
- addrSrv.sin_family = AF_INET;
- addrSrv.sin_port = htons(8888);
- connect(sockClient, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR));
- while(1)
- {
- char szOpenType[20] = {0};
- char szParaName[50] = {0};
- // 客户端发消息给服务端, 触发服务端RPC函数执行, 这样, 就感觉是客户端进程在调用服务器进程里面的函数, 爽歪歪啊!
- scanf("%s", szOpenType);
- scanf("%s", szParaName);
- char szMsg[100] = {0};
- sprintf(szMsg, "%s %s", szOpenType, szParaName); // 其实, sprintf不太安全哈
- send(sockClient, szMsg, strlen(szMsg) + 1, 0);
- }
- closesocket(sockClient);
- WSACleanup();
- return 0;
- }
好, 开启客户端。
下面是执行结果:
我们看到, 客户端远程调用到了服务端的函数, 这就是所谓的RPC. 在实际代码调测中,
我们经常需要主动触发某一函数或某一部分代码的执行, 一般来说, 怎么方便怎么触发, 本文介绍的RPC触发方式是值得考虑的一种方法。
通过本文的学习, 我们也算初步了解了RPC吧。
用C代码简要模拟实现一下RPC(远程过程调用)并谈谈它在代码调测中的重要应用【转】的更多相关文章
- .net单元测试——常用测试方式(异常模拟、返回值测试、参数测试、数据库访问代码测试)
最近在看.net单元测试艺术,我也喜欢单元测试,今天介绍一下如何测试异常.如何测试返回值.如何测试模拟对象的参数传递.如何测试数据库访问代码.单元测试框架使用的是NUnit,模拟框架使用的是:Rhin ...
- 利用Python中的mock库对Python代码进行模拟测试
这篇文章主要介绍了利用Python中的mock库对Python代码进行模拟测试,mock库自从Python3.3依赖成为了Python的内置库,本文也等于介绍了该库的用法,需要的朋友可以参考下 ...
- tolua#代码简要分析
简介 tolua#是Unity静态绑定lua的一个解决方案,它通过C#提供的反射信息分析代码并生成包装的类.它是一个用来简化在C#中集成lua的插件,可以自动生成用于在lua中访问Unity的绑定代码 ...
- 编写高质量代码:改善Java程序的151个建议(第一章:JAVA开发中通用的方法和准则)
编写高质量代码:改善Java程序的151个建议(第一章:JAVA开发中通用的方法和准则) 目录 建议1: 不要在常量和变量中出现易混淆的字母 建议2: 莫让常量蜕变成变量 建议3: 三元操作符的类型务 ...
- CODING 代码资产安全系列之 —— 构建全链路安全能力,守护代码资产安全
本文作者:王振威 - CODING 研发总监 CODING 创始团队成员之一,多年系统软件开发经验,擅长 Linux,Golang,Java,Ruby,Docker 等技术领域.近两年来一直在 COD ...
- 也谈谈规范JS代码的几个注意点
也谈谈规范JS代码的几个注意点 写JS代码差不多也有两年了吧,从刚开始的“初生牛犊不怕虎”乱写一通到后来也慢慢知道去规范一下自己写的代码.这种感觉就像是代码是你的作品,你希望它保持一份不仅干净而且也优 ...
- 使用storyboard显示UITableView时,如果不修改系统默认生成的tableView:cellForRowAtIndexPath:方法中的代码,则必须为UITableViewCell注册(填写)重用标识符:identifier.必须要代码方法中的标识符一致.
CHENYILONG Blog 使用storyboard显示UITableView时,如果不修改系统默认生成的tableView:cellForRowAtIndexPath:方法中的代码,则必须为UI ...
- 阿里云代码管理平台 Teambition Codeup(行云)亮相,为企业代码安全护航
2019杭州云栖大会企业协作与研发效能专场,企业协同平台Teambition负责人齐俊元正式发布阿里云自研的代码管理平台Teambition Codeup(行云),Codeup是一款企业级代码管理产品 ...
- 使用java代码动态配置与xml文件结合的方式使用mybatis-generator生成代码配置
1.使用java代码动态配置与xml文件结合的方式使用mybatis-generator生成代码配置 2.上代码:在resources目录下新建:generatorConfiguration.xml文 ...
随机推荐
- 3.11 - 3.12 A day with Google
补了一番游记. 找了一个本科学弟一起去上海游玩.本来老板还要我周一过去讨论寒假阅读的论文,总算是把讨论时间挪到周六了. 兴冲冲地买好车票后就开始期待上海Google office的神秘之旅. upda ...
- BZOJ 2745: [HEOI2012]Bridge
2745: [HEOI2012]Bridge Time Limit: 30 Sec Memory Limit: 128 MBSubmit: 199 Solved: 90[Submit][Statu ...
- React-Router 动画 Animation
React-Router动画实际上和React动画没什么区别,都是使用 'react-addons-css-transition-group' 这个组件:但是,和普通的 React-Router 的 ...
- java使用POI操作XWPFDocument中的XWPFRun(文本)对象的属性详解
java使用POI操作XWPFDocument中的XWPFRun(文本)对象的属性详解 我用的是office word 2016版 XWPFRun是XWPFDocument中的一段文本对象(就是一段文 ...
- CH3101 阶乘分解
题目链接 分解\(n!\)的质因数,输出相应的\(p_i\)和\(c_i\). 其中\(1\leq n\leq 10^6\). 考虑每一个质因子 \(p\) 在 \(n!\) 中出现的次数.显然, ...
- C中有关引用和指针的异同
参考于https://blog.csdn.net/wtzdedaima/article/details/78377201 C语言也学了蛮久的,其实一直都没有用到过或者碰到过引用的例子.前端时间再全面复 ...
- 内存操作函数memmove,memcpy,memset
通过字符串的学习,我们知道字符串操作函数的操作对象是字符串,并且它的结束标志是结束符\0,当然这个说的是不 受限制的字符串函数.然而当我们想要将一段内存的数据复制到另一块内存时,我们不能使用字符串操作 ...
- bzoj千题计划139:bzoj2229: [Zjoi2011]最小割
http://www.lydsy.com/JudgeOnline/problem.php?id=2229 最小割树介绍:http://blog.csdn.net/jyxjyx27/article/de ...
- [Baltic2009]Radio Transmission
bzoj 1355: [Baltic2009]Radio Transmission http://www.lydsy.com/JudgeOnline/problem.php?id=1355 Time ...
- [洛谷P3643] [APIO2016]划艇
洛谷题目链接:[APIO2016]划艇 题目描述 在首尔城中,汉江横贯东西.在汉江的北岸,从西向东星星点点地分布着 \(N\) 个划艇学校,编号依次为 \(1\) 到 \(N\).每个学校都拥有若干艘 ...