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

972 篇文章 329 订阅
147 篇文章 46 订阅

        明: 本文仅仅是一种模拟的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吧。

 

    

  • 2
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值