导言
RCF(Remote Call Framework,远程调用框架)是一个C++的框架。这个框架用来为实现C++程序进程间调用提供一个简单和一致(consistent)的方法。这个框架基于强类型的C/S接口概念,类似于用户所熟悉的CORBA,DCOM这样的中间件。然而,因为RCF只应用于C++,所以可以充分利用C++特性,从而提供一个以相对简单和整洁的方式实现进程间调用。
这是RCF库的第二个版本,第一个版本也可以在CodeProject上找到。
中国有句老话,一例胜千言(我咋没听过?)。所以将以一系列的例子来组织这篇文章,这些例子会覆盖RCF的特性。
基础
我们从一个标准的echo服务器和客户端的例子来开始,这样的例子可以在几乎所有的网络和IPC示例中见到。我们暴露(expose)然后调用一个函数,这个函数接受一个字符串,并且返回一个相同的字符串,使用RCF,服务器端的代码是这样的:
#include RCFIdl.hpp
#include RCFRcfServer.hpp
#include RCFTcpEndpoint.hpp

RCF_BEGIN(I_Echo, I_Echo)
    RCF_METHOD_R1(std::string, echo, const std::string &)
RCF_END(I_Echo)

class Echo
...{
public:
    std::string echo(const std::string &s)
    ...{
        return s;
    }
};

int main()
...{
    Echo echo;
    RCF::RcfServer server(RCF::TcpEndpoint(50001));
    server.bind<I_Echo>(echo);
    server.startInThisThread();
    return 0;
}
... 客户端代码如下:
#include <RCF/Idl.hpp>

#include <RCF/TcpEndpoint.hpp>


RCF_BEGIN(I_Echo, "I_Echo")
    RCF_METHOD_R1(std::string, echo, const std::string &)
RCF_END(I_Echo)

int main()
...{
    RcfClient<I_Echo> echoClient(RCF::TcpEndpoint("localhost", 50001));
    std::string s = echoClient.echo(RCF::Twoway, "what's up");
    return 0;
}
I_Echo是用RCF_BEGIN/RCF_METHOD/RCF_END宏进行定义的一个接口。这些接口对应于CORBA里的IDL定义,但是在这里,接口定义是被放在C++的源代码里,所以并不需要另外的编译步骤。服务器端和客户端代码简单地包含这些接口,然后和其他的代码一起编译。
客户端桩(stub)中的参数RCF::Twoway用来告诉RCF采用一个two-way方式的客户端调用,这种方式下,客户端发送一个请求并且等待响应,如果在一定时间内没有收到响应(这个时间是可配的),将会抛出一个异常。另一个选项是RCF::Oneway,这种方式下,如果服务端没有发送响应,客户端调用桩会立即把控制返回给用户。
在客户端调用中,把这个双向实参(directional argument)作为第一个参数,可以在代码里清楚地知道远程调用是采用哪种方式。一般说来,远程调用都会被规划为看起来像本地调用一样(正统的RPC观点),但在我看来,透明更重要一些。然而,如果你愿意,通过不传递那个双向实参(directional argument)从而以RPC风格来进行一个远程调用(这时调用是以two-way方式进行的)。
客户端桩时没有进行任何同步操作,所以应该在同一个线程里进行访问。服务端尽管是支持多线程,但在上面的例子中,还是以一个线程来运行的。RcfServer::startInThisThread()劫持了调用线程,并把它变为一个工作线程。
可以通过调用RcfServer::start(false)然后重复调用RcfServer::cycle()来达到相同的效果。在多线程版本中,也可以调用RcfServer::start(),然后驱动服务器的现场将会被自动创建。多线程版本需要Boost.Threads库,并且要定义RCF_USE_BOOST_THREADS预处理符号。
我们也可以用UDP协议来重写上面的客户端和服务器端。这次我们让服务器端和客户端程序运行在一个进程的不同线程里。
#include <RCF/Idl.hpp>
#include <RCF/RcfServer.hpp>
#include <RCF/UdpEndpoint.hpp>

#ifndef RCF_USE_BOOST_THREADS
#error Need to build with RCF_USE_BOOST_THREADS
#endif

RCF_BEGIN(I_Echo, "I_Echo")
    RCF_METHOD_R1(std::string, echo, const std::string &)
RCF_END(I_Echo)

class Echo
...{
public:
    std::string echo(const std::string &s)
    ...{
        return s;
    }
};

int main()
...{
    Echo echo;
    RCF::RcfServer server(RCF::UdpEndpoint(50001));
    server.bind<I_Echo>(echo);
    server.start();
    RcfClient<I_Echo> echoClient(RCF::UdpEndpoint("127.0.0.1", 50001));
    std::string s = echoClient.echo(RCF::Twoway, "what's up");
    server.stop(); // would happen anyway as server object goes out of scope

    return 0;
}
和TCP不同的是UDP是无状态的。数据包不能保证是发送时的顺序被接收到,也不能保证所有的发送的数据包都会被接收到。在像上面的例子的本地连接中,使用two-way方式一般来说是能够正常工作的,因为这些数据包并没有从变幻莫测的真实网络中传输。通常,这种情况应该用one-way方式。
接口
接口定义宏的功能和之前一个版本的RCF是完全一致的。RCF_BEGIN()宏用给定的名字和运行时描述来开始一个接口的定义,RCF_END()宏来结束接口定义。在两者中间,用RCF_METHOD_xx()宏可以定义一共25个接口的成员方法。
RCF_METHOD_xx()宏的后两个字母表示参数的个数和返回类型是否是一个void。比如说,RCF_METHOD_V3用来定义一个三个参数返回值类型为void的方法。
使用这些宏定义了RcfClient<type>类,这里的type是这个接口的名字。这个类直接用作客户端的客户端桩,间接地用作服务器端的服务桩。RCF的接口也可以定义在任意的名字空间内:
namespace A
...{
    namespace B
    ...{
        RCF_BEGIN(I_X, "I_X")
        RCF_METHOD_V0(void, func1)
        RCF_METHOD_R5(int, func2, int, int, int, int, int)
        RCF_METHOD_R0(std::auto_ptr<std::string>, func3)
        RCF_METHOD_V2(void, func4,
           const boost::shared_ptr<std::string> &,
           boost::shared_ptr<std::string> &)
        // ..

        RCF_END(I_X)
    }
}

int main()
...{
    A::B::RcfClient<A::B::I_X> client;
    // or

    A::B::I_X::RcfClient client;
    // ...

}
服务器绑定
在服务器端,接口需要绑定到一个具体的实现上。通过RcfServer::bind()方法来实现这个绑定。根据内存管理方式的不同,绑定有几种变化。下面的几种调用都可以实现一模一样的事情:把一个Echo对象绑定到I_Echo接口上。
...{
    // bind to an object...

    Echo echo;
    server.bind<I_Echo>(echo);

    // or to a std::auto_ptr<>...

    std::auto_ptr<Echo> echoAutoPtr(new Echo());
    server.bind<I_Echo>(echoAutoPtr);

    // or to a boost::shared_ptr<>...

    boost::shared_ptr<Echo> echoPtr(new Echo());
    server.bind<I_Echo>(echoPtr);

    // or to a boost::weak_ptr<>...

    boost::weak_ptr<Echo> echoWeakPtr(echoPtr);
    server.bind<I_Echo>(echoWeakPtr);
}
默认情况下,客户端可以通过接口的名字来使用绑定。服务器端可以通过同一个接口暴露(expose)多个服务器端对象,但是在这种情况下,需要明确指定每个对象的名字:
...{
    RcfServer server(endpoint);

    // bind first object

    Echo echo1;
    server.bind<I_Echo>(echo1, "Echo1");

    // bind second object

    Echo echo2;
    server.bind<I_Echo>(echo2, "Echo2");

    server.start();

    RcfClient<I_Echo> echoClient(endpoint);

    echoClient.getClientStub().setServerBindingName("Echo1");
    std::cout << echoClient.echo("this was echoed by the echo1 object");

    echoClient.getClientStub().setServerBindingName("Echo2");
    std::cout << echoClient.echo("this was echoed by the echo2 object");
}

RCF—用于C++的进程间通讯(1)相关推荐

  1. RCF—用于C++的进程间通讯(3)

    过滤器(Filters) RCF通过过滤器的概念来支持对消息的压缩和加密.过滤器需要同时应用于服务器端和客户端.也可以被应用于传输层,例如应用SSL过滤器到向TCP这样基于流的传输:或者应用于独立的消 ...

  2. RCF—用于C++的进程间通讯(4)

    可扩展性 传输 对于前一个版本的RCF,一个(应得的)批评是关于它和TCP协议过度紧密的关系.现在RCF采用了传输无关的设计,并且对于初用者,可以使用它支持的TCP和UDP协议.更重要的是,它的架构很 ...

  3. Android-Binder进程间通讯机制-多图详解

    本系列: Android-Binder进程间通讯机制-多图详解 一次Binder通信最大可以传输多大的数据?​​​​​​​ 关于Binder (AIDL)的 oneway 机制 概述 最近在学习Bin ...

  4. 管道实现进程间通讯 、WaitNamedPipe

    一.管道实现进程间通讯 主要的理论知识 1.什么是管道以及分类 管道是两个头的东西,每一个头各连接一个进程或者同一个进程的不同代码,依照管道的类别分有两种管道,匿名的和命名的:依照管道的传输方向分也能 ...

  5. linux open 头文件_linux下通过共享内存和mmap实现进程间通讯

    前言 最近在学习GNU/Linux内核,看到mmap的时候书上说: mmap/munmap接口函数是用户最常用的两个系统调用接口,无论是在用户程序中分配内存.读写大文件.链接动态库文件,还是多进程间共 ...

  6. Android(IPC)进程间通讯1:详解Binder由来?

    完整原文:http://tryenough.com/android-... Android开发的进程间通讯,整个Android的应用都依赖于binder做底层通信机制.而Linux中提供的进程间通讯方 ...

  7. linux mmap实例_Linux下通过共享内存和mmap实现进程间通讯(含实例)

    前言 最近在学习GNU/Linux内核,看到mmap的时候书上说: mmap/munmap接口函数是用户最常用的两个系统调用接口,无论是在用户程序中分配内存.读写大文件.链接动态库文件,还是多进程间共 ...

  8. Linux 进程间通讯方式 pipe()函数

    Linux 进程间通讯方式有以下几种: 1->管道(pipe)和有名管道(fifo). 2->消息队列 3->共享内存 4->信号量 5->信号(signal) 6-&g ...

  9. 进程间通讯SendMessage

    PostMessage貌似只能用于进程内通讯,不同进程间通讯可以用SendMessage和共享内存等方式.这里理出SendMessage的用法,方便日后查阅. 发送消息的进程代码: const UIN ...

最新文章

  1. 基于CUDA实现立方体贴图 (Cubemaps) 转换为全景图 (Equirectangular Panorama)
  2. 在WinAPI环境下获得1小时前系统时间
  3. JS数组与对象的遍历方法大全
  4. 讲解SQL Server定时作业job的设置方法
  5. instr函数 mysql_mysql数据库中查找字串出现的位置instr函数
  6. Windows Phone 7 自定义弹出窗口
  7. Github 简明教程 - 操作标签
  8. java 执行查询_在单个语句中用Java执行多个查询
  9. ERROR 1290 (HY000): The MySQL server is running withnbs
  10. 历届二级c语言pdf,历年全国计算机二级C语言题库.pdf
  11. 使用 Iperf 测试软路由性能
  12. 心形函数的几种表达式
  13. AM调制时域代码matlab,AM调制的FPGA实现
  14. 《精通python设计模式》读书笔记之——行为型设计模式
  15. 记梦之三:我成了萧峰
  16. Python可视化基础----从0学会matplotlib折线图,条形图,散点图
  17. 2018.10.27 bzoj1984: 月下“毛景树”(树链剖分)
  18. MCV 和 MTV框架基本信息
  19. Microsoft Visual Studio 2019介绍之使用入门
  20. Scalar数据类型

热门文章

  1. java早餐点餐外卖网站系统
  2. 堡垒机JumpServer(六):内网管理云端服务器
  3. 006网易-表达式求值
  4. 大尺寸共阴数码管驱动电路
  5. 微信小程序 开发 “婚礼邀请函” 微信小程序入门可看
  6. 迅雷【任务配置文件错误,无法继续下载】解决方法
  7. 交通信息服务器图片,交通标志图片大全(图文解释)
  8. 前端开发者应该知道的 Centos/Dokcer/Nginx/Node/Jenkins 操作( 长文)
  9. electron中引入iohook来监听系统级鼠标键盘事件
  10. BeanUtils.populate(Object Bean,Map properties)