VC语言

本类阅读TOP10

·VC++ 学习笔记(二)
·用Visual C++打造IE浏览器(1)
·每个开发人员现在应该下载的十种必备工具
·教你用VC6做QQ对对碰外挂程序
·Netmsg 局域网聊天程序
·Windows消息大全
·VC++下使用ADO编写数据库程序
·VC++学习笔记(四)
·非法探取密码的原理及其防范
·怎样在VC++中访问、修改注册表

分类导航
VC语言Delphi
VB语言ASP
PerlJava
Script数据库
其他语言游戏开发
文件格式网站制作
软件工程.NET开发
RPC远程过程调用实例剖析之二

作者:未知 来源:月光软件站 加入时间:2005-2-28 月光软件站

RPC远程过程调用实例剖析之二

paddy102

Para4. 一个计算阶层的RPC实例开发过程

Microsoft提供了分布式计算的模型支持. RPC标准最初是作为OSF(开放软件基础)DCE(分布式计算环境)规范的一部分. RPCMicrosoft实现与其它的RPCDCE实现兼容, 例如UNIX服务器. 本节将介绍RPCMicrosoft实现. 文中涉及的一些概念如IDL(interface definition language)等请朋友们自己查找资料理解.

本程序由以下几个文件组成:

  RpcFact.idl

  RpcFact.acf

  RpcFact.h

  RpcFact_c.c

  RpcFact_s.c

RpcFact.c

memstub.h

下面结合实现原理一一道来:

1. 定义接口 (得到RpcFact.idl文件)

  创建一个.idl文件, 为应用程序的远地函数定义一个接口.

// File: RpcFact.idl

// interface header

[

    uuid (C16F6562-520D-11D0-B338-444553540000),  // universally unique identifier,唯一识别这个接// , 它可以被服务器用来注册接口, 以使客户机可以定位这个特殊接口. uuid5位数字组

// ,你可以用Microsoftuuidgen.exe来得到它.

        version (1.0),  // 指定版本号, 那么在同一个网络上就可以同时拥有一个RPC接口的不同版本

        endpoint(“ncalrpc: [myFactorial]”)  // 接口的端点, 它给出了将会使用的网络协议的类型和用来接

// 收接口的请求的地址和端口, ncalrpc 表示Local procedure call

]

// interface text, 指定了组成这个接口的函数, 函数类型不支持int void*

interface  rpcfactorial

{

    long  RpcFactorial([in] long nVal);  // 出现[ ]的部分表示属性

}

// end File RpcFact.idl

2. 应用程序属性配置文件 (得到RpcFact.acf文件)

   .acf文件用来指定应用程序的选项, 这些属性告诉client stub如何对接口请求的捆绑进行处理, 这个问题稍后介绍.

// RpcFact.acf

[

   auto_handle  // 相关属性

]

interface  rpcfactorial

{

}

// end File RpcFact.acf

   3. MIDL编译器编译RpcFact.idl文件

第一种方式, midl.exe /c_text /ms_text /app_config RpcFact.idl   (详细了解请在dos下运行midl.exe /?获取).

第二种方式, 先将RpcFact.idl插入你的Project, Projects—Settings中选取左边框内的RpcFact.idl文件, 选择右边的Custom Build页面, IDL文件指定一个用户定制的编译器. 可以键入如下命令:

midl.exe /c_text /ms_text /app_config $ (InputPath)

经过编译之后, 会生成这几个文件: RpcFact.hRpcFact_s.c RpcFact_c.c

4. 开发RPC服务器

  定义好了一个接口之后, 就需要创建一个响应接口请求的进程, 执行请求的操作并返回所有结果给client. 这些任务就由RPC服务器来完成.

 (1) 执行计算的过程

    本例中就是阶层函数的实现, 我把它单独放在一个RpcFact.c文件中.

// File: RpcFact.c

#include <windows.h>

#include “RpcFact.h”  // MIDL编译器生成

long Factorial (long nVal)

{

   long nResult = 1;

   for (; nVal>0; nVal--)

      nResult *= nVal;

   return nResult;

}

// end File RpcFact.c

(2) RPC服务器实体

  使RpcFact.c真正对RPC有用的工作是在服务器实体(RpcFact_s.c)中实现的. 实体内的代码负责建立RPC接口的捆绑, 并用名称服务程序来注册它们及侦听RPC请求.

// File: RpcFact_s.c

#include <windows.h>

#include <iostream.h>

#include <rpc.h>

#include “RpcFact.h”

#include “memstub.h”   // 实现RPC函数的存储分配, 稍后介绍

main()

{

    RPC_BINDING_VECTOR*  bindVector;

    RPC_STATUS  lRetVal;

    // 注册所有可行的协议序列, 所支持的协议由在RpcFact.idl的端点定义中的字符串指定

    // 参数rpcfactorial_v1_0_s_ifspec定义在RpcFact.h, MIDL编译生成

if (lRetVal = RpcServerUseAllProtseqsIf(1, rpcfactorial_v1_0_s_ifspec, NULL))

{

        cout<<”Error in RpcServerUseAllProtseqsIf”<<lRetVal<<endl;

        return 1;

    }

// 注册所支持的接口

    if (RpcServerRegisterIf(rpcfactorial_v1_0_s_ifspec, NULL, NULL))

{

    cout<<”Error in RpcServerRegister”<<endl;

    return 1;

}

// 将接口的捆绑输出到名称服务程序

if (RpcServerInqBindings(&bindVector))

{

    cout<<”Error in RpcServerInqBindings”<<endl;

    return 1;

}

if (RpcServerBindingExport(RPC_C_NS_SYNTAX_DEFAULT, (UCHAR*)”/.: /autorpc”, rpcfactorial_v1_0_s_ifspec, bindVector, NULL))

{

    cout<<”Error in RpcServerBidingExport”<<endl;

    return 1;

}

// 侦听RPC请求

cout<<”Calling RpcServerListen”<<endl;

if (RpcServerListen(1, 5, FALSE))

{

    cout<<”Error in RpcServerListen”<<endl;

    return 1;

}

return 0;

}// end main

// end File RpcFact_s.c

 

// File: memstub.h

// 以下两个函数在RpcFact.h中已经声明

void __RPC_FAR * __RPC_USER MIDL_user_allocate(size_t len)

{

    return (new (unsigned char [len]));

}

void __RPC_USER MIDL_user_free( void __RPC_FAR* ptr)

{

    delete ptr;

}

// end File memstub.h

(3) 建立服务器

建立服务器时, 你需要确保连接server stub函数(RpcFact_s.c)编译后的.obj文件. 此外还得添加两个RPC运行库(rpcns4.librpcrt4.lib).

5. 开发RPC客户机

  // File: RpcFact_c.c

  #include <windows.h>

  #include <iostream.h>

  #include <rpc.h>

  #include <stdlib.h>

  #include “RpcFact.h”

  #include “memstub.h”

  main()

{

      long nVal;

      cout<<”Calling RPC Factorial”<<endl;

      nVal = RpcFactorial(5);

      cout<<”RpcFact returns: “<<nVal<<endl;

      return 0;

  }

  // end File RpcFact_c.c

 

至此, 一个简单的RPC调用示例已经完成, 文中没讲清楚的地方请参看[1][2][3]列出的书籍, 或者你也可以与我联系.

本文的后续篇将继续介绍RPC中的参数传递捆绑到RPC服务器的几种方式以及RPC的异常处理.

 

 

参考书籍:

[1] David Bennett等著. <<Visual C++ 5开发人员指南>>. 机械工业出版社

[2] <<分布式操作系统>>

[3] MSDN 6.0

 




相关文章

相关软件