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

posted @ 2022-11-22 22:29  是谁走漏了消息  阅读(462)  评论(0编辑  收藏  举报