Windows RPC 远程过程调用 初探
Windows RPC 远程过程调用 初探
参考资料
https://bbs.pediy.com/thread-262291.htm Windows RPC 远程过程调用---初理解
RPC简单理解
RPC(Remote procedure call 远程过程调用),一种通过网络从远程计算机上请求服务,而不需要了解底层网络技术的协议。
我的理解,RPC协议的主要目的是做到不同服务间调用方法像同一服务间调用本地方法一样。
RPC Demo(自己实现一个简单rpc调用)
开发环境
windows10
visual studio 2019
在vs2019中建立一个工程
需要建立的文件
IDL文件
ACF文件
定义IDL文件
import "oaidl.idl";
import "ocidl.idl";
//接口头 包含此接口的信息,UUID和版本号,客户端、服务器只有版本兼容,才能进行链接
[
uuid(C964A8F8-2A8A-451D-A540-1200DA9272E6),
//uuid(aaf3c26e-2970-42db-9189-f2bc0e073e7c),
version(1.0)
]
//接口体 接口体中包含的是接口(函数)的原型
interface HelloCrispr
{
void printHello([in, string] unsigned char* pszInput);
void add(int x, int y);
}
定义ACF文件
//接口头
[
implicit_handle (handle_t test_Binding) //test_Binding 序列化句柄
]
//接口体
interface HelloCrispr
{
}
直接编译工程,会看到如下文件
rpc_client(使用上面生成的rpcDemo_*完成调用)
//rpc_client.exe
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include "rpcDemo_h.h"
#include <windows.h>
#pragma comment(lib,"RpcRT4.lib")
void Rpc_port();
void Rpc_socket();
void main()
{
//Rpc_port(); //本地调用
Rpc_socket(); //远程调用
}
/******************************************************/
/* MIDL allocate and free */
/******************************************************/
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);
}
void Rpc_port()
{
printf("%s", "This is RPC port\r\n");
RPC_STATUS status;
unsigned char* pszUuid = NULL;
unsigned char* pszProtocolSequence_port = (unsigned char*)L"ncacn_np"; //https://learn.microsoft.com/zh-cn/windows/win32/rpc/choosing-a-protocol-sequence
unsigned char* pszEndpoint_port = (unsigned char*)L"\\pipe\\useless";
unsigned char* pszNetworkAddress_port = NULL;
unsigned char* pszOptions = NULL;
unsigned char* pszStringBinding = NULL;
unsigned char* pszString = (unsigned char*)"hello, world";
unsigned long ulCode;
status = RpcStringBindingCompose((RPC_WSTR)pszUuid,
(RPC_WSTR)pszProtocolSequence_port,
(RPC_WSTR)pszNetworkAddress_port,
(RPC_WSTR)pszEndpoint_port,
(RPC_WSTR)pszOptions,
(RPC_WSTR*)&pszStringBinding);
if (status) exit(status);
status = RpcBindingFromStringBinding((RPC_WSTR)pszStringBinding, &test_Binding);
if (status) exit(status);
RpcTryExcept
{
printHello(pszString);
add(111,222);
}
RpcExcept(1)
{
ulCode = RpcExceptionCode();
printf("Runtime reported exception 0x%lx = %ld\n", ulCode, ulCode);
}
RpcEndExcept
status = RpcStringFree((RPC_WSTR*)&pszStringBinding);
if (status) exit(status);
status = RpcBindingFree(&test_Binding);
if (status) exit(status);
exit(0);
}
void Rpc_socket()
{
printf("%s", "This is RPC socket\r\n");
RPC_STATUS status;
unsigned char* pszUuid = NULL;
unsigned char* pszProtocolSequence_tcp = (unsigned char*)L"ncacn_ip_tcp";
unsigned char* pszNetworkAddress_tcp = (unsigned char*)L"192.168.1.102"; //服务器地址
unsigned char* pszEndpoint_tcp = (unsigned char*)L"13521";
unsigned char* pszOptions = NULL;
unsigned char* pszStringBinding = NULL;
unsigned char* pszString = (unsigned char*)"hello, world";
unsigned long ulCode;
status = RpcStringBindingCompose((RPC_WSTR)pszUuid,
(RPC_WSTR)pszProtocolSequence_tcp,
(RPC_WSTR)pszNetworkAddress_tcp,
(RPC_WSTR)pszEndpoint_tcp,
(RPC_WSTR)pszOptions,
(RPC_WSTR*)&pszStringBinding);
if (status) exit(status);
status = RpcBindingFromStringBinding((RPC_WSTR)pszStringBinding, &test_Binding);
if (status) exit(status);
RpcTryExcept
{
printHello(pszString);
add(111,222);
}
RpcExcept(1)
{
ulCode = RpcExceptionCode();
printf("Runtime reported exception 0x%lx = %ld\n", ulCode, ulCode);
}
RpcEndExcept
status = RpcStringFree((RPC_WSTR*)&pszStringBinding);
if (status) exit(status);
status = RpcBindingFree(&test_Binding);
if (status) exit(status);
exit(0);
}
rpc_server
//rpc_server.cpp
#include <tchar.h>
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include "rpcDemo_h.h"
#include <windows.h>
#pragma comment(lib,"RpcRT4.lib")
#if 1
extern "C" {
}
void printHello(unsigned char* pszInput)
{
printf("%s\n", pszInput);
MessageBox(0, (LPCWSTR)pszInput, 0, 0);
}
void add(int x, int y) {
printf("[*] x+y=%d", x + y);
MessageBox(0, _T("123"), 0, 0);
}
#endif // 0
void Rpc_port();
void Rpc_socket();
int main()
{
//Rpc_port();
Rpc_socket();
}
/******************************************************/
/* MIDL allocate and free */
/******************************************************/
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);
}
void Rpc_port()
{
printf("%s", "This is RPC port\r\n");
RPC_STATUS status;
unsigned char* pszProtocolSequence_port = (unsigned char*)L"ncacn_np";
unsigned char* pszEndpoint_port = (unsigned char*)L"\\pipe\\useless";
unsigned char* pszSecurity = NULL;
unsigned int cMinCalls = 1;
unsigned int fDontWait = FALSE;
//通过调用这个例程,让 RPC 运行时使用指定的协议序列
status = RpcServerUseProtseqEp((RPC_WSTR)pszProtocolSequence_port,
RPC_C_LISTEN_MAX_CALLS_DEFAULT,
(RPC_WSTR)pszEndpoint_port,
pszSecurity);
printf("[*] 运行时使用指定的协议序列 %d\r\n", status);
if (status) exit(status);
//注册接口 useless_v1_0_s_ifspec在.h文件中会提供
status = RpcServerRegisterIf(HelloCrispr_v1_0_s_ifspec,
NULL,
NULL);
if (status) exit(status);
//这个例程用于让服务器监听到达的远程过程调用
printf("[*] 开始监听 ==> %s\r\n", pszEndpoint_port);
status = RpcServerListen(cMinCalls,
RPC_C_LISTEN_MAX_CALLS_DEFAULT,
fDontWait);
if (status) exit(status);
}
#if 1
void Rpc_socket()
{
printf("%s", "This is RPC socket\r\n");
RPC_STATUS status;
unsigned char* pszProtocolSequence_tcp = (unsigned char*)L"ncacn_ip_tcp";
unsigned char* pszEndpoint_tcp = (unsigned char*)L"13521";
unsigned char* pszSecurity = NULL;
unsigned int cMinCalls = 1;
unsigned int fDontWait = FALSE;
//通过调用这个例程,让 RPC 运行时使用指定的协议序列
status = RpcServerUseProtseqEp((RPC_WSTR)pszProtocolSequence_tcp,
RPC_C_PROTSEQ_MAX_REQS_DEFAULT,
(RPC_WSTR)pszEndpoint_tcp,
pszSecurity);
printf("[*] 运行时使用指定的协议序列 %d\r\n", status);
if (status) exit(status);
//注册接口 useless_v1_0_s_ifspec在.h文件中会提供
status = RpcServerRegisterIfEx(HelloCrispr_v1_0_s_ifspec, NULL, NULL, RPC_IF_ALLOW_CALLBACKS_WITH_NO_AUTH, 0, NULL);
if (status) exit(status);
//这个例程用于让服务器监听到达的远程过程调用
status = RpcServerListen(cMinCalls,
RPC_C_LISTEN_MAX_CALLS_DEFAULT,
fDontWait);
if (status) exit(status);
}
#endif // 0
效果
电脑B运行rpc_client.exe 电脑A执行的rpc_server.exe