windows RPC示例

本文介绍了Windows RPC的基础知识,包括IDL接口定义语言,RPC如何简化分布式应用开发,以及从Standalone Application到分布式服务的过程。通过编译IDL文件生成客户端代理和服务器存根,并在服务端应用中使用,最后探讨了隐式和显式句柄在多服务器RPC调用中的作用。
摘要由CSDN通过智能技术生成

参考文章:
https://www.codeproject.com/Articles/4837/Introduction-to-RPC-Part-1

IDL

Interface Definition Language

主要就是用来描述接口的,语法和C很像但又不完全一样,它可以比C更详细地描述接口的相关细节

Remote Procedure Call (RPC)

RPC技术主要应用在创建分布式应用上

RPC runtime library处理了大部分与网络协议和通信相关的细节,因此我们只需要关注应用的逻辑实现即可,网络相关的操作都由RPC runtime Library做了

使用RPC技术,我们可以在不同的操作系统之间进行过程调用,比如我们可以编译一个适用于linux的服务端,然后编译一个适用于win32的客户端,这样的应用依然是可以正常运行的

The Standalone Application

Standalone Application不会使用rpc技术,他就是一个简单的helloworld,稍后我们会将它转变成一个分布式应用

Hello Lonely World

Standalone.cpp

#include <iostream>
//这是我们将来的服务端应用
void Output(const char* szOutput)
{
   std::cout << szOutput << std::endl;
}

int main()
{
   //这是我们将来的客户端调用
   Output("Hello Lonely World!");
}

直接运行我们这个代码的话,就会输出Hello Longely World!

The IDL File

现在我们来定义我们的IDL文件
File Example1.idl

[
   // 这个UUID是接口的唯一标识符,可以使用SDK中的uuidgen生成
   uuid(00000001-EAF3-4A7A-A0F2-BCE4C30DA77E),

   // uuidgen的版本号
   version(1.0),

   // 声明该接口使用implicit binding handle,handle名叫做hExample1Binding
   implicit_handle(handle_t hExample1Binding)
]
// 接口名称就叫做Example1
interface Example1 
{
   // 声明一个方法,接受一个以 \0 结束的字符串作为参数
   void Output(
      [in, string] const char* szOutput);
}

稍后我们将会讨论一下implicit_handle

What’s Next?

在这里插入图片描述

我们使用sdk中的midl.exe编译我们之前编写的idl文件,midl.exe会根据我们的idl文件生成一个client proxy和server stub,就是两个.c文件,稍后我们会使用cl.exe将他们编译成可执行文件

How May I Serve You?

是时候将我们生成的文件用到我们的服务端应用中了

Hello Server World!

Example1Server.cpp

#include <iostream>
#include "Example1.h"

// Server function.
void Output(const char* szOutput)
{
   std::cout << szOutput << std::endl;
}

// Naive security callback.
RPC_STATUS CALLBACK SecurityCallback(RPC_IF_HANDLE /*hInterface*/, void* /*pBindingHandle*/)
{
    return RPC_S_OK; // Always allow anyone.
}

int main()
{
   RPC_STATUS status;

   // Uses the protocol combined with the endpoint for receiving
   // remote procedure calls.
   status = RpcServerUseProtseqEp(
      reinterpret_cast<unsigned char*>("ncacn_ip_tcp"), // Use TCP/IP protocol.
      RPC_C_PROTSEQ_MAX_REQS_DEFAULT, // Backlog queue length for TCP/IP.
      reinterpret_cast<unsigned char*>("4747"),         // TCP/IP port to use.
      NULL);                          // No security.

   if (status)
      exit(status);

   // Registers the Example1 interface.
   status = RpcServerRegisterIf2(
      Example1_v1_0_s_ifspec,              // Interface to register.
      NULL,                                // Use the MIDL generated entry-point vector.
      NULL,                                // Use the MIDL generated entry-point vector.
      RPC_IF_ALLOW_CALLBACKS_WITH_NO_AUTH, // Forces use of security callback.
      RPC_C_LISTEN_MAX_CALLS_DEFAULT,      // Use default number of concurrent calls.
      (unsigned)-1,                        // Infinite max size of incoming data blocks.
      SecurityCallback);                   // Naive security callback.

   if (status)
      exit(status);

   // Start to listen for remote procedure
   // calls for all registered interfaces.
   // This call will not return until
   // RpcMgmtStopServerListening is called.
   status = RpcServerListen(
     1,                                   // Recommended minimum number of threads.
     RPC_C_LISTEN_MAX_CALLS_DEFAULT,      // Recommended maximum number of threads.
     FALSE);                              // Start listening now.

   if (status)
      exit(status);
}

// Memory allocation function for RPC.
// The runtime uses these two functions for allocating/deallocating
// enough memory to pass the string to the server.
void* __RPC_USER midl_user_allocate(size_t size)
{
    return malloc(size);
}

// Memory deallocation function for RPC.
void __RPC_USER midl_user_free(void* p)
{
    free(p);
}

implicit handle 和explicit handle

我知道为什么这篇文章的作者说explicit handle可以实现客户端同时连接多个服务器进行RPC调用了

因为explicit handle要求在进行RPC时将handle作为参数出传递给远程主机,而客户端连接哪台主机就取决于我们初始化handle时传入的服务器地址参数,因为进行RPC时可以将handle作为参数,那么我们就可以同时初始化多个handle,然后作为参数传递给远程接口,这样我们的客户端就可以同时对多个主机发起RPC,示例代码是这样的

// File Example1ExplicitClient.cpp
#include <iostream>
#include "../Example1Explicit/Example1Explicit.h"

int main()
{
   RPC_STATUS status;
   unsigned char* szStringBinding1 = NULL;
   unsigned char* szStringBinding2 = NULL;

   // Creates a string binding handle.
   // This function is nothing more than a printf.
   // Connection is not done here.
   status = RpcStringBindingCompose(
      NULL, // UUID to bind to.
      reinterpret_cast<unsigned char*>("ncacn_ip_tcp"), // Use TCP/IP
                                                        // protocol.
      reinterpret_cast<unsigned char*>("192.168.80.146"), // TCP/IP network
                                                     // address to use.
      reinterpret_cast<unsigned char*>("4747"), // TCP/IP port to use.
      NULL, // Protocol dependent network options to use.
      &szStringBinding1); // String binding output.

   if (status)
      exit(status);

    status = RpcStringBindingCompose(
      NULL, // UUID to bind to.
      reinterpret_cast<unsigned char*>("ncacn_ip_tcp"), // Use TCP/IP
                                                        // protocol.
      reinterpret_cast<unsigned char*>("192.168.80.130"), // TCP/IP network
                                                     // address to use.
      reinterpret_cast<unsigned char*>("4747"), // TCP/IP port to use.
      NULL, // Protocol dependent network options to use.
      &szStringBinding2); // String binding output.

   if (status)
      exit(status);

   handle_t hExample1ExplicitBinding1 = NULL;
   handle_t hExample1ExplicitBinding2 = NULL;

   // Validates the format of the string binding handle and converts
   // it to a binding handle.
   // Connection is not done here either.
   status = RpcBindingFromStringBinding(
      szStringBinding1, // The string binding to validate.
      &hExample1ExplicitBinding1); // Put the result in the explicit
                                  // binding handle.

   if (status)
      exit(status);

   status = RpcBindingFromStringBinding(
      szStringBinding2, // The string binding to validate.
      &hExample1ExplicitBinding2); // Put the result in the explicit
                                  // binding handle.

   if (status)
      exit(status);

   RpcTryExcept
   {
      // Calls the RPC function. The hExample1ExplicitBinding binding handle
      // is used explicitly.
      // Connection is done here.
		 Output(hExample1ExplicitBinding1, "192.168.80.146");
		Output(hExample1ExplicitBinding2, "192.168.80.130");
   }
   RpcExcept(1)
   {
      std::cerr << "Runtime reported exception " << RpcExceptionCode()
                << std::endl;
   }
   RpcEndExcept

   // Free the memory allocated by a string.
   status = RpcStringFree(
      &szStringBinding1); // String to be freed.

   if (status)
      exit(status);

   status = RpcStringFree(
      &szStringBinding2); // String to be freed.

   if (status)
      exit(status);

   // Releases binding handle resources and disconnects from the server.
   status = RpcBindingFree(
      &hExample1ExplicitBinding1); // Frees the binding handle.

   if (status)
      exit(status);

     status = RpcBindingFree(
      &hExample1ExplicitBinding2); // Frees the binding handle.

   if (status)
      exit(status);
}

// Memory allocation function for RPC.
// The runtime uses these two functions for allocating/deallocating
// enough memory to pass the string to the server.
void* __RPC_USER midl_user_allocate(size_t size)
{
    return malloc(size);
}

// Memory deallocation function for RPC.
void __RPC_USER midl_user_free(void* p)
{
    free(p);
}

效果如下:

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值