由淺入深,舉例講解RPC(一)
關于RPC的文章很多,但是系統講解的很少。下面我將寫一個系列報道。用代碼和論述來把rpc來講講清楚。
這篇就是開始第一篇了。
由于工作比較忙。我們抽出一個星期的時間,有時間會寫一點。把這個系列寫完。所以,有可能每個系列都比較短些。
從最基本的講起,讓大家徹底明白RPC.
好了廢話不多說了。正是開始。
首先,你要用RPC,必須先搞清楚什么是IDL.
Rpc是什么?
http://www.shnenglu.com/alantop/archive/2007/07/09/27717.html
IDL是什么?
http://www.shnenglu.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.shnenglu.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); } |
posted on 2007-07-09 12:41 AlanTop 閱讀(4659) 評論(3) 編輯 收藏 引用 所屬分類: COM 、C++