1、创建IDL文件,定义接口。

IDL文件可以由uuidgen.exe创建。

首先找到系统中uuidgen.exe的位置,如:C:\Program Files\Microsoft Visual Studio 9.0\Common7\Tools。在此目录下运行命令"uuidgen

/i /ohello.idl",即可在该位置生成一个IDL文件:hello.idl。文件内容如下:

//hello.idl

[

uuid(b2617491-ba5a-48a9-b388-9f0cee8ec882),

version(1.0)

]

interface INTERFACENAME

{

}

然后,增加接口。如下:

//hello.idl

[

uuid(b2617491-ba5a-48a9-b388-9f0cee8ec882),

version(1.0)

]

interface INTERFACENAME

{

void HelloProc([in,string]unsigned char* szhello);

void ShutDown(void);

}

2、创建acf文件。

hello.acf文件内容如下:

//hello.acf

[

implicit_handle (handle_t hello_IfHandle)

]

interface INTERFACENAME

{

}

注意: 1)hello.idl文件与hello.acf文件中的接口名称(INTERFACENAME)应一致,否则接下来编译的时候会报错。

 2)hello.idl文件与hello.acf文件应放在同一目录下。

3、编译IDL文件。

有资料说可以用"midl hello.idl"命令直接进行编译,但是我试过之后,总是提示MIDL1005 的错误,没办法,用vs2008进行编译的,步骤如下

首先,创建一个空的项目,如RpcTest将编辑好的hello.idl文件添加至RpcTest项目中。

然后,直接进行编译。

这时就可以看到RpcTest项目的生成目录下有了hello_h.h, hello_c.c, hello_s.c三个文件。其中,hello_h.h文件是客户端和服务器端程序共

同要用到的,hello_c.c是客户端程序需要的,hello_s.c是服务器程序所需要的。

在hello_h.h文件中可以看到hello.idl中所定义的接口实体,一个全局句柄变量(handle_t)以及客户端与服务端的接口句柄名

INTERFACENAME_v1_0_c_ifspec和INTERFACENAME_v1_0_s_ifspec。客户端、服务端应用程序在实时调用将使用接口句柄名。



/* interface INTERFACENAME */

/* [implicit_handle][version][uuid] */ 

void HelloProc(/* [string][in] */ unsigned char *szhello);

void ShutDown( void);

extern handle_t hello_IfHandle;

extern RPC_IF_HANDLE INTERFACENAME_v1_0_c_ifspec;

extern RPC_IF_HANDLE INTERFACENAME_v1_0_s_ifspec;

4、编写服务器程序。

服务端通过调用RPC实现函数RpcServerUseProtseqEp 与RpcServrRegisterIf捆绑信息并提供给客户端,例子程序传递接口句柄名给

RpcServerRegisterIf,其它的参数被置为空,客户端然后调用RpcServerListen函数等待客户端的请求。

服务端应用程序必须包含两个内存管理函数midl_user_allocate与midl_user_free。当远端过程调用向服务端传递参数时,调用这两个函数分

配及释放内存。

除此之外,服务端还应实现具体的接口函数功能。详细代码如下。

//server.cpp

#include <iostream>

using namespace std;

#include "hello_h.h"

int main(void)

{

 RPC_STATUS status = 0;

unsigned int mincall = 1;

 unsigned int maxcall = 20;

status = RpcServerUseProtseqEp(

   (unsigned char *)"ncacn_np",

   maxcall,

   (unsigned char *)"\\pipe\\hello",

   NULL);

 if(status != 0){

  cout<<"RpcServerUseProtseqEp returns: "<<status<<endl;

  return -1;

 }

status = RpcServerRegisterIf(

  INTERFACENAME_v1_0_s_ifspec,

  NULL,

  NULL);

 if(status != 0){

  cout<<"RpcServerRegisterIf returns: "<<status<<endl;

  return -1;

 }

cout<<"Rpc Server Begin Listening..."<<endl;

 status = RpcServerListen(mincall, maxcall, FALSE);

 if(status != 0){

  cout<<"RpcServerListen returns: "<<status<<endl;

  return -1;

 }

cin.get();

 return 0;

}

/************************************************************************/

/*                        MIDL malloc & free                            */

/************************************************************************/

void * __RPC_USER MIDL_user_allocate(size_t len)

{

 return (malloc(len));

}

void __RPC_USER MIDL_user_free(void*ptr)

{

 free(ptr);

}

/************************************************************************/

/*                       Interfaces                                     */

/************************************************************************/

void HelloProc(unsigned char *szhello)

{

 cout<<szhello<<endl;

}

void ShutDown(void)

{

 RPC_STATUS status = 0;

status = RpcMgmtStopServerListening(NULL);

 if(status != 0){

  cout<<"RpcMgmtStopServerListening returns: "<<status<<"!"<<endl;

 }

status = RpcServerUnregisterIf(NULL, NULL, FALSE);

 if(status != 0){

  cout<<"RpcServerUnregisterIf returns: "<<status<<"!"<<endl;

 }

}

5、编译服务端程序。

再次利用刚才的空项目RpcTest。

1)首先将刚刚加入的hello.idl文件从项目中移除。

2)然后加入hello_h.h, hello_s.c, server.cpp三个文件。

3)为项目加入rpc库文件:rpcrt4.lib。

4)编译生成RpcTest.exe,更名为server.exe。

6、编写客户端程序。

hello_c.c 源文件中定义了hello_h.h,它由MIDL生成,在它内部又预定义了rpc.h与rncndr.h它们包含了客户端、服务端应用程序所使用的实时

程序及数据类型,客户端管理着它到服务端的连接,客户端应用程序调用实时函数建立用来连接服务端的句柄,当远端过程调用完成时再释放

它。RpcStringBindingCompose 把代表句柄和为字符串绑定而配置内存的成份组装成字符串。RpcBindingFromStringBinding 根据上一个字符

串为客户端应用程序创建一个服务端绑定句柄。接口端点的指定,方法很多,最终方式取决于使用的协议,例子中使用的是Named pipes,它使

用的IDL字符串是“ncacn_np”,则终点名称就填写”\\pipes\\idlfilename”。

RPC异常处理通过一整套宏处理可以使你控制外部应用程序代码出错引起的异常现象,如有发生,将会调用RpcExcept模块,在这里你需要清除

内存并安全退出。远端过程调用结束后,客户端首先调用RpcStringFree函数,释放设置字符串捆绑的内存,然后调用RpcBindgFree()去释放句

柄。

详细代码如下。

//client.cpp

#include <iostream>

#include <string>

using namespace std;

#include "hello_h.h"

void doRpcCall();

int main(int argc, char** argv)

{

 int i = 0;

 RPC_STATUS status = 0;

unsigned char * pszNetworkAddr = NULL;

 unsigned char * pszStringBinding = NULL;

for(i = 1; i < argc; i++){

  if(strcmp(argv[i], "-ip") == 0){

   pszNetworkAddr = (unsigned char*)argv[++i];

   break;

  }

 }

status = RpcStringBindingCompose(NULL,

   (unsigned char *) "ncacn_np",

   pszNetworkAddr,

   (unsigned char *)"\\pipe\\hello",

   NULL,

   &pszStringBinding);

 if(status != 0){

  cout<<"RpcStringBindingCompose returns: "<<status<<"!"<<endl;

  return -1;

 }

cout<<"pszStringBinding = "<<pszStringBinding<<endl;

 status = RpcBindingFromStringBinding(pszStringBinding, &hello_IfHandle);

 if(status != 0){

  cout<<"RpcBindingFromStringBinding returns: "<<status<<"!"<<endl;

  return -1;

 }

doRpcCall();

status = RpcStringFree(&pszStringBinding);

 if(status != 0)

  cout<<"RpcStringFree returns: "<<status<<"!"<<endl;

status = RpcBindingFree(&hello_IfHandle);

 if(status != 0)

  cout<<"RpcBindingFree returns: "<<status<<"!"<<endl;

cin.get();

 return 0;

}

void doRpcCall(void)

{

 char buff[1024];

 RpcTryExcept{

  while(true){

   cout<<"Please input a string param for Rpc call:"<<endl;

   cin.getline(buff, 1023);

   if(strcmp(buff, "exit") == 0 || strcmp(buff, "quit") == 0){

    ShutDown();

   }

   else{

    HelloProc((unsigned char*)buff);

    cout<<"call helloproc succeed!"<<endl;

   }

  }

 }

RpcExcept(1){

  unsigned long ulCode = RpcExceptionCode();   

  cout<<"RPC exception occured! code: "<<ulCode<<endl;

 }

 RpcEndExcept

}

void * __RPC_USER MIDL_user_allocate(size_t len)   

{   

 return (malloc(len));   

}

void __RPC_USER MIDL_user_free(void* ptr)   

{   

 free(ptr);   

}

7、编译客户端程序。

再次利用刚才的空项目RpcTest。

1)首先将刚刚加入的hello_h.h等文件从项目中全部移除。

2)然后加入hello_h.h, hello_c.c, client.cpp三个文件。

3)为项目加入rpc库文件:rpcrt4.lib。

4)编译生成RpcTest.exe,更名为client.exe。

8、大功告成。

OK,到现在,已经有了客户端、服务端应用程序的可执行文件。

1)首先运行server.exe。

2)而后,在client.exe所在的目录下用命令行"client.exe -ip 192.168.1.146"来启动客户端程序并与服务器端相连。

3)在client的窗口内输入任意字符串,回车后可看到server窗口上有显示。

4)在client窗口内输入exit或quit,server窗口关闭。

RPC远程过程调用实例详解的更多相关文章

  1. RPC框架调用过程详解

    RPC框架调用过程详解 2017年09月16日 21:14:08 荷叶清泉 阅读数 6275   版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. ...

  2. linux基础-磁盘阵列(RAID)实例详解

    磁盘阵列(RAID)实例详解 raid技术分类 软raid技术 硬raid技术 Raid和lvm的区别 为什么选择用raid RAID详解 RAID-0 RAID-1 RAID-5 Raid-10 R ...

  3. Cocos2d-x 3.X手游开发实例详解

    Cocos2d-x 3.X手游开发实例详解(最新最简Cocos2d-x手机游戏开发学习方法,以热门游戏2048.卡牌为例,完整再现手游的开发过程,实例丰富,代码完备,Cocos2d-x作者之一林顺和泰 ...

  4. JavaScript学习笔记-实例详解-类(二)

    实例详解-类(二)   //===给Object.prototype添加只读\不可枚举\不可配置的属性objectId(function(){ Object.defineProperty(Object ...

  5. JavaScript学习笔记-实例详解-类(一)

    实例详解-类(一): //每个javascript函数(除了bind())都自动拥有一个prototype对象// 在未添加属性或重写prototype对象之前,它只包含唯一一个不可枚举属性const ...

  6. Entity Framework实例详解

    Entity Framework Code First的默认行为是使用一系列约定将POCO类映射到表.然而,有时候,不能也不想遵循这些约定,那就需要重写它们.重写默认约定有两种方式:Data Anno ...

  7. 免费的HTML5连载来了《HTML5网页开发实例详解》连载(二)

    最近新浪.百度.腾讯.京东.大众点评.淘宝等流行的网站都加大了招聘HTML5的力度,HTML5开发人员成了抢手货,本次连载的是由大众点评前端工程师和一淘网前端工程师基情奉献的<HTML5网页开发 ...

  8. Linux下rz命令使用的实例详解

    Linux中rz命令和sz命令都可用于文件传输,而rz命令主要用于文件的上传,下面将通过几个实例来给大家详细介绍下Linux下rz命令的用法,一起来学习下吧. rz命令可以批量上传文件,当然也可上传单 ...

  9. 实例详解 DB2 排序监控和调优

    实例详解 DB2 排序监控和调优http://automationqa.com/forum.php?mod=viewthread&tid=2882&fromuid=2

随机推荐

  1. (转)Unity UI之GUI使用

    一:GUI技术介绍 二:常见基础控件使用 三:GUILayout自动布局 四:GUI皮肤 一:GUI技术介绍 GUI技术看似成为古老的技术,但是Unity5.x之后并没有取消这种UI传统的技术.Uni ...

  2. centos 7 中安装Oracle 12c

    今天有需要在centos 7上安装oracle 12 所以上网查了一下安装流程,原贴转自:https://blog.csdn.net/github_39294367/article/details/7 ...

  3. springmvc Cacheable

    直接上代码: <cache:annotation-driven /> <bean id="cacheManager" class="org.spring ...

  4. 如何定义一个BUG

    一.划分一个bug的等级 bug等级主要分为致命.严重.一般.轻微或者建议四个等级: 1.致命错误:系统无法执行.崩溃或严重资源不足.应用模块无法启动或异常退出.无法测试.造成系统不稳定.价值较高功能 ...

  5. CSIC_716_20191127【组合,封装、类的私有属性方法、property装饰器】

    组合 what?   组合是指一个对象中,包含另一个或多个对象. why?      减少代码的冗余. How?     在类中加入其他类的对象,实现跨类对象之间的联动. 耦合度  软件设计要 高内聚 ...

  6. mui框架开发aop的跨页面传值

    mui开发跨平台app,其实不乏会涉及到跨页面传值,今天给大家简单介绍一种常用也是简单的传值方法 咱在这里设置一个场景,就是两个页面进入到同一页面展示不同的元素,此时需要在这两个页面各自设置一个区别的 ...

  7. 关于SecureCRT链接服务器出现乱码的问题

    连接到服务器,选择上方的“选项”->“会话选项”->“外观”->右边的字符编码->utf-8

  8. NX二次开发-UFUN创建块UF_MODL_create_block1

    NX9+VS2012 #include <uf.h> #include <uf_modl.h> UF_initialize(); UF_FEATURE_SIGN Sign = ...

  9. (转)ab(apachebench)测试与loadrunner

    转:http://blog.csdn.net/gzh0222/article/details/7172341 ab的全称是ApacheBench,是 Apache 附带的一个小工具,专门用于 HTTP ...

  10. word2vec中关于霍夫曼树的

    再谈word2vec 标签: word2vec自然语言处理NLP深度学习语言模型 2014-05-28 17:17 16937人阅读 评论(7) 收藏 举报  分类: Felven在职场(86)    ...