用C代码简要模拟实现一下RPC(远程过程调用)并谈谈它在代码调测中

说明: 本文仅仅是一种模拟的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 xxxchar 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"); // 请替换为合适的ipaddrSrv.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;} 好, 开启客户端。

下面是执行结果:

而消极的人则在每个机会都看到某种忧患。

用C代码简要模拟实现一下RPC(远程过程调用)并谈谈它在代码调测中

相关文章:

你感兴趣的文章:

标签云: