博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
用C代码简要模拟实现一下RPC(远程过程调用)并谈谈它在代码调测中的重要应用
阅读量:4141 次
发布时间:2019-05-25

本文共 3878 字,大约阅读时间需要 12 分钟。

        明: 本文仅仅是一种模拟的RPC实现, 真正的RPC实现还是稍微有点复杂的。

 

        我们来看看下面这个常见的场景: 在某系统中,我们要对某一函数进行调测, 但是, 很难很难构造出这个函数被调用的实际场景, 怎么办?

        虽然很难构造出这个函数被调用的实际场景, 但我们完全可以在代码中主动调用这个函数啊。多想方法(直接方法和间接方法), 少找借口, 并且坚信方法总是存在的。我们可以搞一个触发的操作, 每触发一次, 就调用到该系统中的该函数。 可是, 如果这个系统比较封闭, 比如是某嵌入式系统, 也不好触发。 没关系, 我们借用RPC的思路来实现: 让这个系统做服务端, 然后在客户端上触发。

 

        什么是RPC(远程过程调用)呢?度娘介绍了很多, 我不想搞那么复杂, 所以用一句白话来解释RPC: 进程A向进程B发送消息, 触发进程B的函数被执行,这样, 从形式上看, 好像就是进程A远程调用了进程B的函数, 这就是所谓的RPC(实际上, 进程A仅仅是触发而已, 真正执行的仍然是进程B, 但理解为进程A远程调用了进程B的函数, 也是很爽的)

        下面, 基于上面介绍的代码调测场景, 我来简要实现一下RPC:

 

        服务端程序为(进程B):

 

#include 
#include
// 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 
#include
#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吧。

 

    

你可能感兴趣的文章
python循环语句与C语言的区别
查看>>
vue 项目中图片选择路径位置static 或 assets区别
查看>>
vue项目打包后无法运行报错空白页面
查看>>
Vue 解决部署到服务器后或者build之后Element UI图标不显示问题(404错误)
查看>>
element-ui全局自定义主题
查看>>
facebook库runtime.js
查看>>
vue2.* 中 使用socket.io
查看>>
openlayers安装引用
查看>>
js报错显示subString/subStr is not a function
查看>>
高德地图js API实现鼠标悬浮于点标记时弹出信息窗体显示详情,点击点标记放大地图操作
查看>>
初始化VUE项目报错
查看>>
vue项目使用安装sass
查看>>
HTTP和HttpServletRequest 要点
查看>>
在osg场景中使用GLSL语言——一个例子
查看>>
laravel 修改api返回默认的异常处理
查看>>
laravel事务
查看>>
【JavaScript 教程】浏览器—History 对象
查看>>
这才是学习Vite2的正确姿势!
查看>>
7 个适用于所有前端开发人员的很棒API,你需要了解一下
查看>>
25个构建Web项目的HTML建议,你需要了解一下!
查看>>