文档章节

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

moki_oschina
 moki_oschina
发布于 2014/08/18 17:24
字数 1651
阅读 1279
收藏 3

基础

我们从一个标准的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");
}


 

本文转载自:http://www.360doc.com/content/12/0329/14/168576_198940816.shtml

moki_oschina
粉丝 26
博文 202
码字总数 44864
作品 0
成都
程序员
私信 提问
有人要我挑战STL 质量, 很简单.

我很多年没有碰C++了, 下面是10年前的代码, 模板来做到数据类型无关, 用于在多个进程当中实现循环链表,用于消息队列. 新的版本,用一个局部对象,来实现锁. 实现这个的目的是在于通过设置固定大...

宏哥
2012/10/12
9.9K
132
中国最大的互联网综合服务提供商之一.招聘1.后台开发高级工程师.2.客户端开发工程师.

一.后台开发高级工程师.岗位职责:负责severh后台开发 1 责任感强,有较强的逻辑思维能力、沟通能力,能够承担工作压力 2 两年以上linux后台开发经历,linux系统熟悉者优先,熟悉网络开发 3 ...

千觅千寻
2011/07/05
745
3
线程同步机制的区别与比较及进程通信方法

有关多线程的一些技术问题: 1、 何时使用多线程? 2、 线程如何同步? 3、 线程之间如何通讯? 4、 进程之间如何通讯? 先来回答第一个问题,线程实际主要应用于四个主要领域,当然各个领域...

AlphaJay
2010/06/02
1K
0
Android 核心分析 之六 -----IPC框架分析 Binder,Service,Se...

我首先从宏观的角度观察Binder,Service,Service Manager,并阐述各自的概念。从Linux的概念空间中,Android的设计Activity托管在不同的的进程,Service也都是托管在不同的进程,不同进程间的...

LiSteven
2013/08/23
134
0
腾讯公司急招高级开发人员若干,年薪15-40万

网络技术开发工程师:要求,了解流媒体传输QoS,有跨平台开发经验者优先。 后台开发、客户端开发工程师:精通C/C++,熟悉多进程编程和进程间通讯,精通汇编语言,有一定逆向功底。 客户端开发...

千觅千寻
2011/08/09
3.4K
9

没有更多内容

加载失败,请刷新页面

加载更多

Redis缓存NoSQL

redis的应用场景有哪些 1、会话缓存(最常用) 2、消息队列,比如支付 3、活动排行榜或计数 4、发布、订阅消息(消息通知) 5、商品列表、评论列表等

BobwithB
17分钟前
2
0
「绘画技巧」一分钟画出动漫人物的喜怒哀乐中“喜”的各种表情

「绘画技巧」一分钟画出动漫人物的喜怒哀乐中“喜”的各种表情 表情拥有着可以凸显动漫人物情绪和主张的魔力,表情渲染整个环境。那么今天来和大家一起分享自己整理收集动漫人物喜怒哀乐中的...

知北
20分钟前
3
0
从流中的三种求和方式谈起

//使用reduce()方法int reduce = Arrays.asList(ins).stream().reduce(0, Integer::sum);//Collectors类的工厂方法,收集器int collect1 = Arrays.asList(ins).stream().collect(Colle......

我的眼里只有眼屎
21分钟前
2
0
File类的使用(文件与文件夹,获取,判断存在,删除,)

//File类的使用 public static void main(String[] args) throws IOException, ClassNotFoundException { //test3();// File f = new File("E:\\资料\\第二阶段\\d......

zhengzhixiang
24分钟前
2
0
58到家MySQL军规升级版

转载 2018-03-30 58到家DBA 架构师之路 一、基础规范 表存储引擎必须使用InnoDB 表字符集默认使用utf8,必要时候使用utf8mb4 解读: 通用,无乱码风险,汉字3字节,英文1字节 utf8...

xiaolyuh
32分钟前
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部