前言:
编写一个win32 RPC demo
具体内容:
1:编写IDL(Interface Description Language,接口描述语言):
test.idl:
[
uuid("F211474B-E9DF-4682-B779-DFAA64B56F9F"),
version(1.0)
]
interface HelloWorld
{
int intAdd(int x, int y);
}
注:uuid可以使用vs自动create guid工具生成,具体在 tools->create GUID
在编写一个应用程序配置文件(.acf),它的作用是对RPC接口进行配置:
test.acf:
[
implicit_handle(handle_t test_Binding)
]
interface HelloWorld
{
}
编译idl文件:
在cmd或者vs终端运行命令:
midl test.idl
生成test.h, test_c.c, test_s.c文件,其中test.h为公用头文件,test_c.c为客户端文件,test_s.c为服务端文件
2:编写代码
在visual studio中新建win32 console application工程
Server端:
首先,引入刚才midl生成的test.h 和 test_s.c文件,新建一个调用.cpp文件,文件结构如下图:
其次,引入rpcrt4.lib依赖包,操作过程为:
右键工程属性,在Linker->Input->Additional Dependencies中添加rpcrt4.lib
等这些准备工作做好后,就可以开始书写代码了,具体代码内容如下:
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include "../../../test.h"
int intAdd(int x, int y)
{
printf("%d + %d = %d\n", x, y, x + y);
return x + y;
}
int wmain(int argc, wchar_t* argv[])
{
// 采用tcp协议,13521端口
RpcServerUseProtseqEp((RPC_WSTR)L"ncacn_ip_tcp", RPC_C_PROTSEQ_MAX_REQS_DEFAULT,
(RPC_WSTR)L"13521", NULL);
// 注册,HelloWorld_v1_0_s_ifspec定义域头文件test.h
// 注意:从Windows XP SP2开始,增强了安全性的要求,如果用RpcServerRegisterIf()注册接口,客户端调用时会出现
// RpcExceptionCode() == 5,即Access Denied的错误,因此,必须用RpcServerRegisterIfEx带RPC_IF_ALLOW_CALLBACKS_WITH_NO_AUTH标志
// 允许客户端直接调用
RpcServerRegisterIfEx(HelloWorld_v1_0_s_ifspec, NULL, NULL, RPC_IF_ALLOW_CALLBACKS_WITH_NO_AUTH, 0, NULL);
// 开始监听,本函数将一直阻塞
RPC_STATUS result = RpcServerListen(1, 20, FALSE);
printf("end-------------RPC_STATUS: %d\n", result);
return 0;
}
// 下面的函数是为了满足链接需要而写的,没有的话会出现链接错误
void __RPC_FAR* __RPC_USER midl_user_allocate(size_t len)
{
return(malloc(len));
}
void __RPC_USER midl_user_free(void __RPC_FAR *ptr)
{
free(ptr);
}
注:
a:这里采用tcp的形式进行通信,也可以采用命名管道的方式
b、RpcServerRegisterIfEx调用,具体看注释说明
以上就是服务端的代码
客户端:
前两部操作同服务端,区别是客户端引入的是test_c.c文件
客户端代码如下:
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <locale.h>
#include "../../../test.h"
int wmain(int argc, wchar_t* argv[])
{
if (argc < 2) {
_wsetlocale(LC_ALL, L"chs");
wprintf_s(L"请输入ip地址,格式为 testClient.exe xxx.xxx.xxx.xxx\n");
Sleep(2000);
return 0;
}
wprintf_s(L"server ip: %s\n", argv[1]);
RPC_WSTR pszStringBinding = NULL;
int x, y, rval;
RpcStringBindingCompose(
NULL,
(RPC_WSTR)L"ncacn_ip_tcp",
(RPC_WSTR)argv[1] /*NULL*/,
(RPC_WSTR)L"13521",
NULL,
&pszStringBinding
);
// 绑定接口,这里要和 test.acf 的配置一致,那么就是test_Binding
RpcBindingFromStringBinding(pszStringBinding, &test_Binding);
// 下面是调用服务端的函数了
RpcTryExcept
{
while (1)
{
printf("Input two integer: ");
scanf_s("%d %d", &x, &y);
rval = intAdd(x, y);
printf("%d\n", rval);
Sleep(2000);
}
}
RpcExcept(1)
{
printf("RPC Exception %d\n", RpcExceptionCode());
Sleep(2000);
}
RpcEndExcept
// 释放资源
RpcStringFree(&pszStringBinding);
RpcBindingFree(&test_Binding);
return 0;
}
// 下面的函数是为了满足链接需要而写的,没有的话会出现链接错误
void __RPC_FAR* __RPC_USER midl_user_allocate(size_t len)
{
return(malloc(len));
}
void __RPC_USER midl_user_free(void __RPC_FAR *ptr)
{
free(ptr);
}
运行后结果如下:
由于是本机运行,所以直接输入了localhost,如果换成其他机器 可以输入对应ip地址
demo地址:
https://download.csdn.net/download/herojuice/10537284
说明:
以上内容大部分来自网上,这里稍做了一些整理,这里仅做记录总结