這幾天因爲工作的需要,學習了一下RPC進程通信,RPC確實是個好東西啊,可以遠程,可以本機,可以跨系統,而且處理過程,以及消息傳遞非常隱祕,安全性極高,函數的實現過程全部是在服務器端,而所有的客戶端本身也可以作爲一個服務器,也就是所有的程序初始化的時候都建立一個RPC的服務,這樣所有的進程就想訪問誰就訪問誰了。
首先,第一步,是要通過IDL生成接口,提供給程序使用,代碼很簡單,我就添加三個簡單的函數:
import "oaidl.idl";
import "ocidl.idl";
[
uuid(EA5B1108-7593-423e-8C05-313BF6E62CC2),
version(1.0)
]
interface hw
{
void Hello( [in, string] const char * szOutput );
void SendMessageEx( [in,string] const char * szMsg );
int Add([in] const int Add1,[in] const int Add2);
}
然後編譯成功後生成三個文件rpc_h.h , rpc_c.c , rpc_s.c,這三個函數分別的用途是第一個:聲明函數和一些其他的信息,後面兩個分別是client和server端的定義的一些代碼,我們單純的使用就好。
接下來,我們來寫server端的代碼:
<pre name="code" class="cpp">#include"stdafx.h"
#include<stdio.h>
#include<stdlib.h>
#include "../rpc_five/rpc_h.h" //重點的兩個文件要包含進去另外還有兩個靜態庫
#include "../rpc_five/rpc_s.c"
#pragma comment(lib,"rpcrt4")
#pragma comment(lib,"ole32")
void Hello(handle_t IDL_handle,const unsigned char*psz){
printf("server:%s\n",psz);
}
//////////////SendMessageEx/////////////////////////////////
void SendMessageEx(handle_t IDL_handle, const unsigned char *szMsg)
{
char Temp[16];
sprintf( Temp ,"%s" , szMsg );
if ( 0 == strcmp(Temp,"quit"))
{
RpcMgmtStopServerListening(NULL);
RpcServerUnregisterIf(NULL,NULL,FALSE);
}
printf("sendmessage->%s\n",Temp);
}
////////////////////////////////////////////////////////////
int Add(handle_t IDL_handle, const int Add1, const int Add2)
{
printf("Sum = %d",Add1 + Add2);
return Add1 + Add2;
}
void Shutdown(handle_t IDL_handle){
RpcMgmtStopServerListening(NULL);
RpcServerUnregisterIf(NULL,NULL,FALSE);
}
void* __RPC_USER midl_user_allocate(size_t len){ //這兩段代碼的用途是防止編譯出錯的
return(malloc(len));
}
void __RPC_USER midl_user_free(void __RPC_FAR* ptr){
free(ptr);
}
int main()
{
RPC_STATUS status;
status = RpcServerUseProtseqEp(
(RPC_CSTR)("ncacn_ip_tcp"), //表面使用TCP/IP協議,另外還有三個,管道,RPC,UDP協議
RPC_C_PROTSEQ_MAX_REQS_DEFAULT, //max長度
(RPC_CSTR)("888"), //端口號
NULL); //安全屬性
if (status)
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>printf("ServerUse failed\n");
<span style="white-space:pre"> </span>exit(status);
<span style="white-space:pre"> </span>}
else
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>printf("UseProtseqEq ok\n");
<span style="white-space:pre"> </span>}
//<span style="white-space:pre"> </span>RpcServerRegisterIf(hw_v1_0_s_ifspec, NULL, NULL); 普通版本的註冊,個人覺得不好用,建議使用加強版
RpcServerRegisterIfEx(
hw_v1_0_s_ifspec, // 接口名稱
NULL,
NULL,
RPC_IF_ALLOW_CALLBACKS_WITH_NO_AUTH,
RPC_C_LISTEN_MAX_CALLS_DEFAULT,
NULL);
if (status)
<span style="white-space:pre"> </span>{
printf("Register failed\n");
exit(status);
<span style="white-space:pre"> </span>}
else
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>printf("Register if ok\n");
<span style="white-space:pre"> </span>}
status = RpcServerListen( 1,RPC_C_LISTEN_MAX_CALLS_DEFAULT,FALSE ); //建立之後處於阻塞監聽狀態
if (status)
<span style="white-space:pre"> </span>{
printf("Server listen failed\n");
exit(status);
<span style="white-space:pre"> </span>}
else
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>printf("listen ok\n");
}
<span style="white-space:pre"> </span>return 0;
}
客戶端程序其實跟服務器端程序寫法差不多:
#include "stdafx.h"
#include "windows.h"
#include "stdio.h"
#include "../rpc_five/rpc_h.h"
#include "../rpc_five/rpc_c.c"
#pragma comment(lib,"rpcrt4")
#pragma comment(lib,"ole32")
<span style="white-space:pre"> </span>int main()
<span style="white-space:pre"> </span>{
RPC_STATUS status;
RPC_BINDING_HANDLE hwBinding;
unsigned char* szStringBinding=NULL;
status=RpcStringBindingCompose(//建立一個String Binding句柄,並不連接
NULL,
(RPC_CSTR)("ncacn_ip_tcp"),
(RPC_CSTR)("127.0.0.1"),
(RPC_CSTR)("888"),
NULL,
(RPC_CSTR*)&szStringBinding);
if(status){
printf("StringBinding failed\n");
exit(status);}
printf("szString=%s\n",szStringBinding);
status=RpcBindingFromStringBinding(
szStringBinding,
&hwBinding);
if(status){
printf("Bind from String failed:%d\n",GetLastError());
exit(status);}
RpcTryExcept{
while ( 1 )
{
printf("請輸入指令:");
RPC_CSTR Temp[16];
scanf("%s",&Temp);
SendMessageEx(hwBinding,(RPC_CSTR)Temp);
int Add1,Add2,Sum;
printf("請輸入2個任意整數:");
scanf("%d %d",&Add1,&Add2);
Sum = Add(hwBinding,Add1,Add2);
printf("Sum = %d",Sum);
}
Hello(hwBinding,(RPC_CSTR)("Thank u for use it"));
}
RpcExcept(1){
printf("Runtime reported exception:%d,except=%d\n",GetLastError(),RpcExceptionCode());
}
RpcEndExcept
status = RpcBindingFree(&hwBinding);
RpcStringFree(&szStringBinding);
if (status){
printf("Bind free failed\n");
exit(status);}
return 0;
}
void* __RPC_USER midl_user_allocate(size_t size){
return malloc(size);
}
void __RPC_USER midl_user_free(void* p){
free(p);
}