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

基础

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

时间: 2024-10-10 06:02:02

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

linux进程间通讯-System V IPC 信号量

进程间通信的机制--信号量.注意请不要把它与之前所说的信号混淆起来,信号与信号量是不同的两种事物.有关信号的更多内容,可以阅读我的另一篇文章:Linux进程间通信--使用信号.下面就进入信号量的讲解. 一.什么是信号量 为了防止出现因多个程序同时访问一个共享资源而引发的一系列问题,我们需要一种方法,它可以通过生成并使用令牌来授权,在任一时刻只能有一个执行线程访问代码的临界区域.临界区域是指执行数据更新的代码需要独占式地执行.而信号量就可以提供这样的一种访问机制,让一个临界区同一时间只有一个线程在

ACE框架 基于共享内存的进程间通讯

ACE框架将基于共享内存的进程间通讯功能,如其它IO组件或IPC组件一样,设计成三个组件.流操作组件ACE_MEM_Stream,连接器组件ACE_MEM_Connector,以及接收连接组件ACE_MEM_Accpter.ACE框架为基于共享内存的进程间通讯提供了两种数据传输(分发deliver)策略.一种是使用生产者-消费者队列的一对多的多用户MT策略,另一种是使用socket流的可以使用反应器响应数据接收事件的Reactor策略.不论哪一种策略都要通过socket进行TCP连接,并进行进程

Android AIDL 进行进程间通讯(IPC)

编写AIDL文件时,需要注意: 1.接口名和aidl文件名相同. 2.接口和方法前不用加访问权限修饰符 (public.private.protected等,也不能用final.static). 3.AIDL默认支持的类型包括java基本类型 (int.long.boolean等) 和 (String.List.Map.CharSequence),使用这些类型时不需要import声明.对于List和Map中的元素类型必须是AIDL支持的类型,如果使用自定义类型作为参数或者返回值,自定义类型必须实

Android进阶笔记04:Android进程间通讯之Messenger ( 区别于AIDL)

一. Android进程间通讯之Messenger 的引入 (1)引言:      平时一说进程间通讯,大家都会想到AIDL,其实messenger和AIDL作用一样,都可以进行进程间通讯.它是基于消息的进程间通信,就像子线程和UI线程发送消息那样,是不是很简单,还不用去写AIDL文件,是不是有点小爽.哈哈.此外,还支持记录客户端对象的Messenger,然后可以实现一对多的通信:甚至作为一个转接处,任意两个进程都能通过服务端进行通信. (2) Messenger 与 AIDL 比较:    

Android进程间通讯之messenger

这两天在看binder,无意间在文档看到messenger这么个东西,感觉这个东西还挺有意思的,给大家分享一下. 平时一说进程间通讯,大家都会想到AIDL,其实messenger和AIDL作用一样,都可以进行进程间通讯.它是基于消息的进程间通信,就像子线程和UI线程发送消息那样,是不是很简单,还不用去写AIDL文件,是不是有点小爽.哈哈. 此外,还支持记录客户端对象的Messenger,然后可以实现一对多的通信:甚至作为一个转接处,任意两个进程都能通过服务端进行通信. 与 AIDL 比较: 当您

【IPC进程间通讯之一】邮槽MailSlot

IPC进程间通信+邮槽MailSlot         IPC(Inter-Process Communication,进程间通信).        现代计算机采用虚拟内存机制,为进程提供独立的足够大的地址空间,处于安全目的,一个进程不具有特殊的权限,是无法访问另一个进程的内存空间,进程间相互隔绝.进程间通信IPC就需要特别的机制来实现,邮槽MailSlot是常用的IPC方法之一.                 1.邮槽(MailSlot):                 邮槽MailSlo

Windows下的进程间通讯及数据共享

Windows 下的进程间通讯及数据共享 Windows 下有很多方法实现进程间通讯,比如用 socket,管道(Pipe),信箱(Mailslot),等等.但最基本最直接的还是使用内存共享.其他方法最终还是会绕道这里. 可想而知,如果物理内存只有一份,让这份内存在不同的进程中,映射到各自的虚拟地址空间上,每个进程都可以读取同一份数据,是一种最高效的数据交换方法.下面我们就讨论如何实现它. 共享内存在 Windows 中是用 FileMapping 实现的.我们可以用 CreateFileMap

嵌入式OS入门笔记-以RTX为案例:八.RTX的进程间通讯(二)

嵌入式OS入门笔记-以RTX为案例:八.RTX的进程间通讯(二) RTX的进程间通讯主要依赖于四种机制,分别是事件(Event),互斥锁(Mutex),旗语或信号量(Semaphore),和邮箱(Mailbox).前三种机制侧重进程间的同步,邮箱则侧重进程间的数据通讯.这次讲一下信号量和邮箱. 1.信号量(Semaphore) 1.简介 信号量其实是一个很抽象的操作系统原语,它最早由荷兰计算机科学家Dijkstra提 出,用于解决多项资源的分配问题.实际上信号量的适用范围非常广,可以很好地解决很

【IPC进程间通讯之二】管道Pipe

IPC进程间通信+管道Pipe         IPC(Inter-Process Communication,进程间通信).         管道用于进程间共享数据,其实质是共享内存,常用IPC之一.管道不仅可以用于本机进程间通信,还可实现跨网络进程间通信,如同Socket通信,管道同样封装计算机底层网络实现,提供一个良好的API接口.                1.管道(Pipe):        管道分为匿名管道和命名管道.        匿名管道只能用于父子进程间通信 ,不能跨网络通