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

摘要:
虽然很难构造调用此函数的实际场景,但我们可以在代码中主动调用此函数。执行触发过程B的功能。进程A似乎远程调用了进程B的功能,但可以理解,进程A远程调用了过程B的功能。让我简单地实现RPC:[cpp]viewplaincopy#include<标准时间>

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

  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 ");  
  12. }  
  13.   
  14. // RPC函数(Remote Procedure Calling)  
  15. void readMask()  
  16. {  
  17.     printf("mask is 255.255.255.0 ");    
  18. }  
  19.   
  20. // RPC函数(Remote Procedure Calling)  
  21. void readGateway()  
  22. {  
  23.     printf("gateway is 192.168.1.1 ");   
  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 ");  
  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 ");  
  47.             continue;  
  48.         }  
  49.   
  50.         if(0 != strcmp(szOperType, "read"))  
  51.         {  
  52.             printf("type error ");  
  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 ");  
  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. }  

      好, 开启客户端。


      下面是执行结果:

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

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

免责声明:文章转载自《用C代码简要模拟实现一下RPC(远程过程调用)并谈谈它在代码调测中的重要应用【转】》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇30分钟全面解析-SQL事务+隔离级别+阻塞+死锁利用itext生成pdf的简单例子下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

arcgispro 计算字段示例

计算字段示例 round(!Shape.area!,1) 使用键盘输入值并不是编辑表中值的唯一方式。在某些情况下,为了设置字段值,可能要对单条记录甚至是所有记录执行数学计算。您可以对所有记录或选中记录执行简单计算和高级计算。此外,还可以在属性表中的字段上计算面积、长度、周长和其他几何属性。以下各部分包括使用字段计算器的若干示例。计算将通过 Python 执...

Eclipse中启动Tomcat服务器产生错误的原因及解决方案

弄了一个下午才弄好,就是出现这样的错误,纠结了一个下午,现在拿出来分享一下!希望对各位朋友有用!Eclipse中启动Tomcat服务器产生错误通常有以下几种: 1.严重: Error initializing endpoint java.net.BindException: Address already in use:...

程序延时里的思维

程序延时里的思维   大概所有的51单片机初学者在用到延时的时候都有一个共同点,那就是使用一段空循环消耗CPU的时间从而达到延时目的,常见的函数就是图1-1中的delay函数。这种模式在初学阶段的确是简单易懂,学习起来会得心应手,这可以称得上是我们单片机生涯的童年时代,它使我们学会了走起来。但对于学习了三四年单片机的人来说,不能再单单走了,要跑起来! 1...

得到控制台窗口的句柄

得到控制台窗口的句柄 调用 GetConsoleTitle() 来保存当前的控制台窗口标题。 调用 SetConsoleTitle() 来将控制台标题更改为一个唯一的标题。 调用 Sleep(40),以确保已更新窗口标题。 调用 FindWindow(NULL, uniquetitle),以获取 HWND,此调用将返回 HWND, 如果操作失败,将返回...

pcntl_fork()函数说明

pcntl_fork()函数复制了当前进程的PCB,并向父进程返回了派生子进程的pid,父子进程并行,打印语句的先后完全看系统的调度算法,打印的内容控制则靠pid变量来控制。因为我们知道pcntl_fork()向父进程返回了派生子进程的pid,是个正整数;而派生子进程的pid变量并没有被改变,这一区别使得我们看到了他们的不同输出。 1. 派生子进程的进程,...

iOS 强制退出程序APP代码

1、先po代码 // 退出程序 1 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 UIAlertView* alert = [[UIAlertView alloc] initWithTitle:self.exitapplica...