关于RPC的文章很多,但是系统讲解的很少。下面我将写一个系列报道。用代码和论述来把rpc来讲讲清楚。
这篇就是开始第一篇了。
 
由于工作比较忙。我们抽出一个星期的时间,有时间会写一点。把这个系列写完。所以,有可能每个系列都比较短些。
从最基本的讲起,让大家彻底明白RPC.
 
好了废话不多说了。正是开始。
 
 
首先,你要用RPC,必须先搞清楚什么是IDL.
 
Rpc是什么? 
http://www.cppblog.com/alantop/archive/2007/07/09/27717.html
IDL是什么?
http://www.cppblog.com/alantop/archive/2007/07/09/27725.html 
 
下来,举个例子。怎么样把一个标准程序改成用IDL语言写的程序。
 
这是一个标准程序。
// File Standalone.cpp #include <iostream>   // Future server function. void Output(const char* szOutput) {    std::cout << szOutput << std::endl; }   int main() {    // Future client call.    Output("Hello Lonely World!"); }  | 
 
下来看我们怎么把它改为一个标准IDL语言的程序
用IDL语言定义接口:
// File Example1.idl [    // A unique identifier that distinguishes this    // interface from other interfaces.    uuid(00000001-EAF3-4A7A-A0F2-BCE4C30DA77E),      // This is version 1.0 of this interface.    version(1.0),      // This interface will use an implicit binding    // handle named hExample1Binding.    implicit_handle(handle_t hExample1Binding) ] interface Example1 // The interface is named Example1 {    // A function that takes a zero-terminated string.    void Output(       [in, string] const char* szOutput); }  | 
上面这个文件是我们用idl语言定义的,我们定义了一个接口Example1, 它带有uuid和version. 这个接口里定义了一个函数Output.
 
UUID是什么?
http://www.cppblog.com/alantop/archive/2007/07/09/27726.html 
 
 
接口的implicit_handle属性,我们后面再讨论。
 
接下来干什么呢?
我们为了在程序中使用idl,必须通过通过编译器(midl.exe)把它翻译成客户代理和服务器存根, 代理和存根将在后面被我们的编译器(windows平台下的cl.exe)所使用。
 

 
改好的服务器端程序:
// File Example1Server.cpp #include <iostream> #include "Example1.h"   // Server function. void Output(const char* szOutput) {    std::cout << szOutput << std::endl; }   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 = RpcServerRegisterIf(       Example1_v1_0_s_ifspec, // Interface to register.       NULL, // Use the MIDL generated entry-point vector.       NULL); // Use the MIDL generated entry-point vector.      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); }  | 
 
这是初始化,和注册接口的代码。
 
现在看看怎么写客户端
// File Example1Client.cpp #include <iostream> #include "Example1.h"   int main() {    RPC_STATUS status;    unsigned char* szStringBinding = 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*>("localhost"), // TCP/IP network                                                      // address to use.       reinterpret_cast<unsigned char*>("4747"), // TCP/IP port to use.       NULL, // Protocol dependent network options to use.       &szStringBinding); // String binding output.      if (status)       exit(status);      // Validates the format of the string binding handle and converts    // it to a binding handle.    // Connection is not done here either.    status = RpcBindingFromStringBinding(       szStringBinding, // The string binding to validate.       &hExample1Binding); // Put the result in the implicit binding                           // handle defined in the IDL file.      if (status)       exit(status);      RpcTryExcept    {       // Calls the RPC function. The hExample1Binding binding handle       // is used implicitly.       // Connection is done here.       Output("Hello RPC World!");    }    RpcExcept(1)    {       std::cerr << "Runtime reported exception " << RpcExceptionCode()                 << std::endl;    }    RpcEndExcept      // Free the memory allocated by a string.    status = RpcStringFree(       &szStringBinding); // String to be freed.      if (status)       exit(status);      // Releases binding handle resources and disconnects from the server.    status = RpcBindingFree(       &hExample1Binding); // Frees the implicit binding handle defined in                           // the IDL file.      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); }  |