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

转自: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):

  1. #include <stdio.h>  
  2. #include <winsock2.h> // winsock接口  
  3. #pragma comment(lib, "ws2_32.lib") // winsock实现  
  4.   
  5. SOCKET sockConn; // 全局的通信socket  
  6.   
  7.   
  8. // RPC函数(Remote Procedure Calling)  
  9. void readIP()  
  10. {  
  11.     printf("ip is 192.168.1.100\n");  
  12. }  
  13.   
  14. // RPC函数(Remote Procedure Calling)  
  15. void readMask()  
  16. {  
  17.     printf("mask is 255.255.255.0\n");    
  18. }  
  19.   
  20. // RPC函数(Remote Procedure Calling)  
  21. void readGateway()  
  22. {  
  23.     printf("gateway is 192.168.1.1\n");   
  24. }  
  25.   
  26. // 消息处理线程  
  27. DWORD WINAPI handleThread(LPVOID pM)    
  28. {  
  29.     while(1)  
  30.     {  
  31.         char szMsg[100] = {0};  
  32.         int nRet = recv(sockConn, szMsg, sizeof(szMsg) - 1, 0);  
  33.         if(nRet <= 0)  
  34.         {  
  35.             printf("recv error\n");  
  36.             closesocket(sockConn);  
  37.             break;  
  38.         }  
  39.   
  40.         // 仅仅考虑读操作, 预期的形式为: read xxx  
  41.         char szOperType[20] = {0};  
  42.         char szParaName[50] = {0};  
  43.         nRet = sscanf(szMsg, "%s %s", szOperType, szParaName);  
  44.         if(2 != nRet)  
  45.         {  
  46.             printf("command error\n");  
  47.             continue;  
  48.         }  
  49.   
  50.         if(0 != strcmp(szOperType, "read"))  
  51.         {  
  52.             printf("type error\n");  
  53.             continue;  
  54.         }  
  55.   
  56.         // 其实, 下面的部分最好用C++ STL的map来做, 为了简便示意, 我就没用map搞了  
  57.         if(0 == strcmp(szParaName, "ip"))  
  58.         {  
  59.             readIP();  
  60.         }  
  61.         else if(0 == strcmp(szParaName, "mask"))  
  62.         {  
  63.             readMask();  
  64.         }  
  65.         else if(0 == strcmp(szParaName, "gateway"))  
  66.         {  
  67.             readGateway();  
  68.         }  
  69.         else  
  70.         {  
  71.             printf("parameter error\n");  
  72.             continue;  
  73.         }  
  74.   
  75.         Sleep(200);  
  76.     }  
  77.   
  78.     return 0;  
  79. }   
  80.   
  81. int main()  
  82. {  
  83.     WORD wVersionRequested;  // 双字节,winsock库的版本  
  84.     WSADATA wsaData;         // winsock库版本的相关信息  
  85.       
  86.     wVersionRequested = MAKEWORD(1, 1); // 0x0101 即:257  
  87.       
  88.   
  89.     // 加载winsock库并确定winsock版本,系统会把数据填入wsaData中  
  90.     WSAStartup( wVersionRequested, &wsaData );  
  91.       
  92.   
  93.     // AF_INET 表示采用TCP/IP协议族  
  94.     // SOCK_STREAM 表示采用TCP协议  
  95.     // 0是通常的默认情况  
  96.     unsigned int sockSrv = socket(AF_INET, SOCK_STREAM, 0);  
  97.   
  98.     SOCKADDR_IN addrSrv;  
  99.   
  100.     addrSrv.sin_family = AF_INET; // TCP/IP协议族  
  101.     addrSrv.sin_addr.S_un.S_addr = inet_addr("0.0.0.0"); // socket对应的IP地址  
  102.     addrSrv.sin_port = htons(8888); // socket对应的端口  
  103.   
  104.     // 将socket绑定到某个IP和端口(IP标识主机,端口标识通信进程)  
  105.     bind(sockSrv,(SOCKADDR*)&addrSrv, sizeof(SOCKADDR));  
  106.   
  107.     // 将socket设置为监听模式,5表示等待连接队列的最大长度  
  108.     listen(sockSrv, 5);  
  109.   
  110.   
  111.     // sockSrv为监听状态下的socket  
  112.     // &addrClient是缓冲区地址,保存了客户端的IP和端口等信息  
  113.     // len是包含地址信息的长度  
  114.     // 如果客户端没有启动,那么程序一直停留在该函数处  
  115.     SOCKADDR_IN addrClient;  
  116.     int len = sizeof(SOCKADDR);  
  117.     sockConn = accept(sockSrv,(SOCKADDR*)&addrClient, &len);  
  118.   
  119.     // 开启消息处理线程  
  120.     HANDLE handle = CreateThread(NULL, 0, handleThread, NULL, 0, NULL);     
  121.   
  122.     while(1); // 卡住, 表示主线程去做自己的事情, 忙自己的东西  
  123.   
  124.     CloseHandle(handle);  
  125.     closesocket(sockConn);    
  126.     closesocket(sockSrv);  
  127.     WSACleanup();  
  128.       
  129.     return 0;  
  130. }  

       启动服务端。


       然后看看客户端(进程A):

  1. #include <winsock2.h>  
  2. #include <stdio.h>  
  3. #pragma comment(lib, "ws2_32.lib")  
  4.   
  5. int main()  
  6. {  
  7.     WORD wVersionRequested;  
  8.     WSADATA wsaData;  
  9.     wVersionRequested = MAKEWORD(1, 1);  
  10.   
  11.     SOCKET sockClient = 0;  
  12.   
  13.     WSAStartup( wVersionRequested, &wsaData );  
  14.     sockClient = socket(AF_INET, SOCK_STREAM, 0);  
  15.     SOCKADDR_IN addrSrv;  
  16.     addrSrv.sin_addr.S_un.S_addr = inet_addr("192.168.1.100"); // 请替换为合适的ip  
  17.     addrSrv.sin_family = AF_INET;  
  18.     addrSrv.sin_port = htons(8888);  
  19.     connect(sockClient, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR));  
  20.   
  21.     while(1)  
  22.     {  
  23.         char szOpenType[20] = {0};  
  24.         char szParaName[50] = {0};  
  25.   
  26.         // 客户端发消息给服务端, 触发服务端RPC函数执行, 这样, 就感觉是客户端进程在调用服务器进程里面的函数, 爽歪歪啊!  
  27.         scanf("%s", szOpenType);  
  28.         scanf("%s", szParaName);  
  29.   
  30.         char szMsg[100] = {0};  
  31.         sprintf(szMsg, "%s %s", szOpenType, szParaName); // 其实, sprintf不太安全哈  
  32.         send(sockClient, szMsg, strlen(szMsg) + 1, 0);  
  33.     }  
  34.   
  35.     closesocket(sockClient);  
  36.     WSACleanup();  
  37.   
  38.     return 0;  
  39. }  

      好, 开启客户端。


      下面是执行结果:



       我们看到, 客户端远程调用到了服务端的函数, 这就是所谓的RPC.  在实际代码调测中, 我们经常需要主动触发某一函数或某一部分代码的执行, 一般来说, 怎么方便怎么触发, 本文介绍的RPC触发方式是值得考虑的一种方法。 通过本文的学习, 我们也算初步了解了RPC吧。

posted @ 2018-03-08 16:36  Sky&Zhang  阅读(926)  评论(0编辑  收藏  举报