RCF教程

RCF_BEGIN(I_HelloWorld, “I_HelloWorld”)
RCF_METHOD_V1(void, Print, const std::string &)
RCF_END(I_HelloWorld)

class HelloWorldImpl{
public:
void Print(const std::string & s){
std::cout << "I_HelloWorld service: " << s << std::endl;
}
};

int main(){
RCF::RcfInitDeinit rcfInit;
HelloWorldImpl helloWorld;
RCF::RcfServer server( RCF::TcpEndpoint(50001) );
server.bind<I_HelloWorld>(helloWorld);
server.start();

std<span class="token operator">::</span>cout <span class="token operator">&lt;&lt;</span> <span class="token string">"Press Enter to exit..."</span> <span class="token operator">&lt;&lt;</span> std<span class="token operator">::</span>endl<span class="token punctuation">;</span>
std<span class="token operator">::</span>cin<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

client

#include <iostream>
#include <RCF/RCF.hpp>

RCF_BEGIN(I_HelloWorld, “I_HelloWorld”)
RCF_METHOD_V1(void, Print, const std::string &)
RCF_END(I_HelloWorld)

int main(){
RCF::RcfInitDeinit rcfInit;
std::cout << “Calling the I_HelloWorld Print() method.” << std::endl;
RcfClient<I_HelloWorld> client( RCF::TcpEndpoint(50001) );
client.Print(“Hello World”);
return 0;
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

使用的transport是一个TCP连接,server监听本地主机(127.0.0.1)接口的50001端口。

在运行这段代码之前,我们需要构建它。要构建RCF,只需将src/RCF/RCF.cpp源文件编译到应用程序中。RCF要求Boost库是可用的,因此你需要下载Boost,1.35.0以后的任何版本都可以。您不需要构建任何Boost库,因为RCF在其默认配置中只使用来自Boost的头文件。

下面是如何使用两个常见的编译器工具集来构建上面的server代码。

1.2 How to build - Visual Studio 2010
  • 在Visual Studio IDE中,选择New Project -> Visual c++ -> Win32 -> Win32 Console Application
  • Application Settings对话框中,选中Empty Project复选框;
  • 在新建Project的Project Properties对话框中,选择C/C++ -> General -> Additional Include Directories
  • 为Boost和RCF添加include路径,例如C:\boost_1_49_0C:\RCF\include
  • 向Project中添加一个Server.cpp文件,并复制粘贴上面的代码;
  • RCF\src\RCF\RCF.cpp添加到Project中;
  • 选择Build -> Build Solution
1.3 How to build - gcc
  • 创建一个Server.cpp文件并将上面的代码复制粘贴到其中;
  • 在同一目录下,运行以下命令:
    g++ Server.cpp /path/to/RCF/src/RCF/RCF.cpp -I/path/to/boost_1_49_0 -I/path/to/RCF/include -lpthread -ldl -oServer
    
       
       
    • 1
    注意:用系统上的实际路径替换/path/to/boost_1_49_0/path/to/RCF
1.4 Running the server and client

让我们启动Sever:

c:\Projects\RcfSample\Debug>Server.exe
Press Enter to exit...

 
 
  • 1
  • 2

然后启动Client:

c:\Projects\RcfSample\Debug>Client.exe
Calling the I_HelloWorld Print() method.

 
 
  • 1
  • 2

在服务器窗口,你现在应该可以看到:

c:\Projects\RcfSample\Debug>Server.exe
Press Enter to exit...
I_HelloWorld service: Hello World

 
 
  • 1
  • 2
  • 3

为了简化本教程的其余部分,我们将重写Hello World示例,以便客户机和服务器在单个进程中运行:

#include <iostream>
#include <RCF/RCF.hpp>

RCF_BEGIN(I_HelloWorld, “I_HelloWorld”)
RCF_METHOD_V1(void, Print, const std::string &)
RCF_END(I_HelloWorld)

class HelloWorldImpl{
public:
void Print(const std::string & s){
std::cout << "I_HelloWorld service: " << s << std::endl;
}
};

int main(){
RCF::RcfInitDeinit rcfInit;

HelloWorldImpl helloWorld<span class="token punctuation">;</span>
RCF<span class="token operator">::</span>RcfServer <span class="token function">server</span><span class="token punctuation">(</span> RCF<span class="token operator">::</span><span class="token function">TcpEndpoint</span><span class="token punctuation">(</span><span class="token number">50001</span><span class="token punctuation">)</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
server<span class="token punctuation">.</span>bind<span class="token operator">&lt;</span>I_HelloWorld<span class="token operator">&gt;</span><span class="token punctuation">(</span>helloWorld<span class="token punctuation">)</span><span class="token punctuation">;</span>
server<span class="token punctuation">.</span><span class="token function">start</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

std<span class="token operator">::</span>cout <span class="token operator">&lt;&lt;</span> <span class="token string">"Calling the I_HelloWorld Print() method."</span> <span class="token operator">&lt;&lt;</span> std<span class="token operator">::</span>endl<span class="token punctuation">;</span>
RcfClient<span class="token operator">&lt;</span>I_HelloWorld<span class="token operator">&gt;</span> <span class="token function">client</span><span class="token punctuation">(</span> RCF<span class="token operator">::</span><span class="token function">TcpEndpoint</span><span class="token punctuation">(</span><span class="token number">50001</span><span class="token punctuation">)</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
client<span class="token punctuation">.</span><span class="token function">Print</span><span class="token punctuation">(</span><span class="token string">"Hello World"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

运行这个程序产生的输出:

Calling the I_HelloWorld Print() method.
I_HelloWorld service: Hello World

 
 
  • 1
  • 2

本教程的其余部分将以这个示例为基础,来演示RCF的一些基本特性。

2. Interfaces and implementations

RCF允许您直接在代码中定义远程接口。在上面的例子中,我们定义了I_HelloWorld接口:

RCF_BEGIN(I_HelloWorld, "I_HelloWorld")
    RCF_METHOD_V1(void, Print, const std::string &)
RCF_END(I_HelloWorld)

 
 
  • 1
  • 2
  • 3

RCF_BEGIN()RCF_METHOD_xx()RCF_END()是宏,用于为远程调用生成client和server存根。

  • RCF_BEGIN()开始接口定义,并定义接口的编译时标识符(I_HelloWorld)和接口的运行时标识符(“I_HelloWorld”)。
  • RCF_METHOD_xx() —— RCF_METHOD_xx()宏定义远程方法。RCF_METHOD_V1()定义了一个远程方法,它接受一个参数(在本例中是const std::string &),并返回void类型。RCF_METHOD_R2()定义了一个带有两个参数和一个非void返回值的远程方法,以此类推。RCF_METHOD_xx()宏是为接受最多15个参数的void和非void远程调用定义的。
  • RCF_END()结束接口定义。

在server上,我们将接口绑定到一个服务对象上:

server.bind<I_HelloWorld>(helloWorld);

 
 
  • 1

让我们向I_HelloWorld接口添加更多的远程方法。我们将添加打印一个字符串列表的方法,并返回打印的字符数:

// Serialization code for std::vector<>.
#include <SF/vector.hpp>

RCF_BEGIN(I_HelloWorld, “I_HelloWorld”)
RCF_METHOD_V1(void, Print, const std::string &)
RCF_METHOD_R1(int, Print, const std::vector<std::string> &)
RCF_METHOD_V2(void, Print, const std::vector<std::string> &, int &)
RCF_END(I_HelloWorld)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

远程调用可以通过一个返回值(与第二个Print()方法一样)返回参数,也可以通过非const引用参数(与第三个Print()方法一样)返回参数。

将这些方法添加到I_HelloWorld接口之后,我们还需要在HelloWorldImpl服务对象中实现它们:

class HelloWorldImpl{
public:
    void Print(const std::string & s){
        std::cout << "I_HelloWorld service: " << s << std::endl;
    }
<span class="token keyword">int</span> <span class="token function">Print</span><span class="token punctuation">(</span><span class="token keyword">const</span> std<span class="token operator">::</span>vector<span class="token operator">&lt;</span>std<span class="token operator">::</span>string<span class="token operator">&gt;</span> <span class="token operator">&amp;</span> v<span class="token punctuation">)</span><span class="token punctuation">{</span>
    <span class="token keyword">int</span> howManyChars <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
    <span class="token keyword">for</span> <span class="token punctuation">(</span>std<span class="token operator">::</span>size_t i<span class="token operator">=</span><span class="token number">0</span><span class="token punctuation">;</span> i<span class="token operator">&lt;</span>v<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token operator">++</span>i<span class="token punctuation">)</span><span class="token punctuation">{</span>
        std<span class="token operator">::</span>cout <span class="token operator">&lt;&lt;</span> <span class="token string">"I_HelloWorld service: "</span> <span class="token operator">&lt;&lt;</span> v<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token operator">&lt;&lt;</span> std<span class="token operator">::</span>endl<span class="token punctuation">;</span>
        howManyChars <span class="token operator">+</span><span class="token operator">=</span> v<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    <span class="token keyword">return</span> howManyChars<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">void</span> <span class="token function">Print</span><span class="token punctuation">(</span><span class="token keyword">const</span> std<span class="token operator">::</span>vector<span class="token operator">&lt;</span>std<span class="token operator">::</span>string<span class="token operator">&gt;</span> <span class="token operator">&amp;</span> v<span class="token punctuation">,</span> <span class="token keyword">int</span> <span class="token operator">&amp;</span> howManyChars<span class="token punctuation">)</span><span class="token punctuation">{</span>
    howManyChars <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
    <span class="token keyword">for</span> <span class="token punctuation">(</span>std<span class="token operator">::</span>size_t i<span class="token operator">=</span><span class="token number">0</span><span class="token punctuation">;</span> i<span class="token operator">&lt;</span>v<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token operator">++</span>i<span class="token punctuation">)</span><span class="token punctuation">{</span>
        std<span class="token operator">::</span>cout <span class="token operator">&lt;&lt;</span> <span class="token string">"I_HelloWorld service: "</span> <span class="token operator">&lt;&lt;</span> v<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token operator">&lt;&lt;</span> std<span class="token operator">::</span>endl<span class="token punctuation">;</span>
        howManyChars <span class="token operator">+</span><span class="token operator">=</span> v<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

};

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

注意,HelloWorldImpl不是派生类。代替使用虚函数,RCF使用基于模板的静态多态性绑定接口到实现上。

下面是调用新的Print()方法的示例client代码:

RcfClient<I_HelloWorld> client( RCF::TcpEndpoint(50001) );

std::vector<std::string> stringsToPrint;
stringsToPrint.push_back(“AAA”);
stringsToPrint.push_back(“BBB”);
stringsToPrint.push_back(“CCC”);

// 远程调用通过返回值返回参数。
int howManyChars = client.Print(stringsToPrint);

// 远程调用通过非const引用参数返回参数。
client.Print(stringsToPrint, howManyChars);

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

输出为:

I_HelloWorld service: AAA
I_HelloWorld service: BBB
I_HelloWorld service: CCC
I_HelloWorld service: AAA
I_HelloWorld service: BBB
I_HelloWorld service: CCC

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

3. Error handling

如果远程调用没有完成,RCF将抛出一个异常,其中包含描述错误条件的错误消息。让我们用try/catch包装远程调用:

try
{
    RcfClient<I_HelloWorld> client( RCF::TcpEndpoint(50001) );
    client.Print("Hello World");
}
catch(const RCF::Exception & e)
{
    std::cout << "Error: " << e.getErrorString() << std::endl;
}

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

我们可以通过注释掉RcfServer::start()调用来模拟服务器宕机:

HelloWorldImpl helloWorld;
RCF::RcfServer server( RCF::TcpEndpoint(50001) );
server.bind<I_HelloWorld>(helloWorld);
//server.start();

 
 
  • 1
  • 2
  • 3
  • 4

运行客户端,我们现在得到:

Error: Client connection to 127.0.0.1:50001 timed out after 2000 ms (server not started?).

 
 
  • 1

RCF抛出的所有异常都派生自RCF::Exception。Exception包含关于错误的各种描述和上下文信息。。您可以调用RCF::Exception::getErrorId()来检索错误代码,调用RCF::Exception::getErrorString()来检索错误的英文翻译,包括任何与错误相关的参数。

如果远程调用的服务器实现抛出异常,则RcfServer将捕获该异常并将其返回给客户机,并将其作为RCF::RemoteException抛出。例如,如果我们用以下服务实现启动服务器:

class HelloWorldImpl
{
public:
    void Print(const std::string & s)
    {
        throw std::runtime_error("Print() service is unavailable at this time.");
        std::cout << "I_HelloWorld service: " << s << std::endl;
    }
};

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

,此时客户端将输出:

Error: Server-side user exception. Exception type: class std::runtime_error. Exception message: "Print() service is unavailable at this time.".

 
 
  • 1

4. Client stubs

远程调用总是通过客户机存根(RCF::ClientStub)进行的。您可以通过调用RcfClient<>::getClientStub()来访问RcfClient<>的客户端存根。客户端存根包含许多影响远程调用执行方式的设置。

两个最重要的设置是连接超时和远程调用超时。连接超时决定RCF在尝试建立到服务器的网络连接时将等待多长时间。远程调用超时决定RCF等待远程调用响应从服务器返回的时间。

要更改这些设置,请调用ClientStub::setConnectionTimeoutMs()和ClientStub::setRemoteCallTimeoutMs()函数:

RcfClient<I_HelloWorld> client( RCF::TcpEndpoint(50001) );

// 5 second timeout when establishing network connection.
client.getClientStub().setConnectTimeoutMs(5*1000);

// 60 second timeout when waiting for remote call response from the server.
client.getClientStub().setRemoteCallTimeoutMs(60*1000);

client.Print(“Hello World”);

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

有关客户端存根的更多信息,请参见远程调用-客户端(Remote calls - Client-side)。

5. Server sessions

在服务器端,RCF为每个到server的client连接维护一个会话(RCF::RcfSession)。一个client连接的RcfSession可通过RCF::getCurrentSession()提供给服务器端代码。您可以使用RcfSession来维护特定于一个特定client连接的应用程序数据。可以通过调用RcfSession::createSessionObject<>()RcfSession::getSessionObject<>()将任意C++对象存储在一个会话中。

例如,要将一个HelloWorldSession对象与每个client连接关联到I_HelloWorld接口,该接口跟踪在连接上发出的调用的次数:

class HelloWorldSession{
public:
    HelloWorldSession() : mCallCount(0){
        std::cout << "Created HelloWorldSession object." << std::endl;
    }
<span class="token operator">~</span><span class="token function">HelloWorldSession</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
    std<span class="token operator">::</span>cout <span class="token operator">&lt;&lt;</span> <span class="token string">"Destroyed HelloWorldSession object."</span> <span class="token operator">&lt;&lt;</span> std<span class="token operator">::</span>endl<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

std<span class="token operator">::</span>size_t mCallCount<span class="token punctuation">;</span>

};

class HelloWorldImpl{
public:
void Print(const std::string & s){
RCF::RcfSession & session = RCF::getCurrentRcfSession();
// 如果会话对象不存在,则创建它。
HelloWorldSession & hwSession = session.getSessionObject<HelloWorldSession>(true);
++hwSession.mCallCount;
std::cout << "I_HelloWorld service: " << s << std::endl;
std::cout << "I_HelloWorld service: " << "Total calls on this connection so far: " << hwSession.mCallCount << std::endl;
}
};

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

不同的RcfClient<>实例将具有不同的到server的连接。这里我们从两个RcfClient<>实例中调用Print()三次:

for (std::size_t i=0; i<2; ++i){
    RcfClient<I_HelloWorld> client( RCF::TcpEndpoint(50001) );
    client.Print("Hello World");
    client.Print("Hello World");
    client.Print("Hello World");
}

// 稍等一会儿,以便server有时间销毁最后一个会话。
RCF::sleepMs(1000);

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

,产生如下输出:

Created HelloWorldSession object.
I_HelloWorld service: Hello World
I_HelloWorld service: Total calls on this connection so far: 1
I_HelloWorld service: Hello World
I_HelloWorld service: Total calls on this connection so far: 2
I_HelloWorld service: Hello World
I_HelloWorld service: Total calls on this connection so far: 3
Destroyed HelloWorldSession object.
Created HelloWorldSession object.
I_HelloWorld service: Hello World
I_HelloWorld service: Total calls on this connection so far: 1
I_HelloWorld service: Hello World
I_HelloWorld service: Total calls on this connection so far: 2
I_HelloWorld service: Hello World
I_HelloWorld service: Total calls on this connection so far: 3
Destroyed HelloWorldSession object.

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

当客户机连接关闭时,将销毁服务器会话和任何关联的会话对象。

有关服务器会话的更多信息,请参见远程调用-服务器端。

6. Transports

RCF使更改远程调用的底层传输变得很容易。传输层由传递给RcfServer和RcfClient<>的端点参数决定。到目前为止,我们一直使用TcpEndpoint来指定TCP传输。

默认情况下,当指定只有端口号的TcpEndpoint时,RCF将使用127.0.0.1作为IP地址。所以下面两个片段是等价的:

RCF::RcfServer server( RCF::TcpEndpoint(50001) );

 
 
  • 1
RCF::RcfServer server( RCF::TcpEndpoint("127.0.0.1", 50001) );

 
 
  • 1

,详情如下:

RcfClient<I_HelloWorld> client( RCF::TcpEndpoint(50001) );

 
 
  • 1
RcfClient<I_HelloWorld> client( RCF::TcpEndpoint("127.0.0.1", 50001) );

 
 
  • 1

127.0.0.1是IPv4回送地址。监听127.0.0.1的服务器只对与服务器位于同一台机器上的客户机可用。您可能希望跨网络运行客户机,在这种情况下,服务器需要监听外部可见的网络地址。最简单的方法是指定0.0.0.0(用于IPv4),或者::0(用于IPv6),这将使服务器监听所有可用的网络接口:

// Server-side.
RCF::RcfServer server( RCF::TcpEndpoint("0.0.0.0", 50001) );

// Client-side.
RcfClient<I_HelloWorld> client( RCF::TcpEndpoint(“Server123”, 50001) );

  • 1
  • 2
  • 3
  • 4
  • 5

RCF还支持许多其他端点类型。要在UDP上运行服务器和客户端,请使用UdpEndpoint:

// Server-side.
RCF::RcfServer server( RCF::UdpEndpoint("0.0.0.0", 50001) );

// Client-side.
RcfClient<I_HelloWorld> client( RCF::UdpEndpoint(“Server123”, 50001) );

  • 1
  • 2
  • 3
  • 4
  • 5

要在命名管道上运行服务器和客户机,请使用NamedPipeEndpoint:

// Server-side.
RCF::RcfServer server( RCF::Win32NamedPipeEndpoint("MyPipe") );

// Client-side.
RcfClient<I_HelloWorld> client( RCF::Win32NamedPipeEndpoint(“MyPipe”) );

  • 1
  • 2
  • 3
  • 4
  • 5

NamedPipeEndpoint映射到Windows系统上的Windows命名管道,以及基于UNIX的系统上的UNIX本地域套接字。

使用UDP进行双向(请求/响应)消息传递通常是不实际的,因为UDP的不可靠语义意味着消息可能不会被传递,或者可能被无序地传递。UDP在单向消息传递场景中非常有用,在单向消息传递场景中,服务器应用程序逻辑对丢失或无序到达的消息具有弹性。

RCF支持通过HTTP和HTTPS协议进行远程调用的隧道传输。HttpEndpoint用于配置HTTP上的隧道。下面是一个客户端通过第三方HTTP代理远程调用服务器的例子:

// Server-side.
HelloWorldImpl helloWorldImpl;
RCF::RcfServer server( RCF::HttpEndpoint("0.0.0.0", 80) );
server.bind<I_HelloWorld>(helloWorldImpl);
server.start();

// Client-side.
// 该客户机将通过在proxy.acme.com:8080端口的HTTP代理连接到server1.acme.com。
RcfClient<I_HelloWorld> client( RCF::HttpEndpoint(“server1.acme.com”, 80) );
client.getClientStub().setHttpProxy(“proxy.acme.com”);
client.getClientStub().setHttpProxyPort(8080);
client.Print(“Hello World”);

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

类似地,RCF::HttpsEndpoint可用于配置HTTPS上的tunneling:

// Server-side.
HelloWorldImpl helloWorldImpl;
RCF::RcfServer server( RCF::HttpsEndpoint("0.0.0.0", 443) );
server.bind<I_HelloWorld>(helloWorldImpl);
RCF::CertificatePtr serverCertPtr( new RCF::PfxCertificate("path/to/certificate.p12", "password", "CertificateName") );
server.setCertificate(serverCertPtr);
server.start();

// Client-side.
// 该客户机将通过在proxy.acme.com:8080端口的HTTP代理连接到server1.acme.com。
RcfClient<I_HelloWorld> client( RCF::HttpsEndpoint(“server1.acme.com”, 443) );
client.getClientStub().setHttpProxy(“proxy.acme.com”);
client.getClientStub().setHttpProxyPort(8080);
client.Print(“Hello World”);

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

HTTPS的证书和证书验证配置为SSL传输协议(请参阅下面的传输协议)。

可以为一个RcfServer配置多个传输。例如,要配置在端口50001上同时接受IPv4和IPv6连接的服务器:

RCF::RcfServer server;
server.addEndpoint( RCF::TcpEndpoint("0.0.0.0", 50001) );
server.addEndpoint( RCF::TcpEndpoint("::0", 50001) );
server.start();

 
 
  • 1
  • 2
  • 3
  • 4

在某些平台上,底层网络堆栈允许您指定::0来监听IPv4和IPv6接口,在这种情况下,这就足够了:

RCF::RcfServer server;
server.addEndpoint( RCF::TcpEndpoint("::0", 50001) );
server.start();

 
 
  • 1
  • 2
  • 3

这是一个服务器接受连接TCP, UDP和命名管道:

RCF::RcfServer server;
server.addEndpoint( RCF::TcpEndpoint("::0", 50001) );
server.addEndpoint( RCF::UdpEndpoint("::0", 50002) );
server.addEndpoint( RCF::Win32NamedPipeEndpoint("MyPipe") );
server.start();

 
 
  • 1
  • 2
  • 3
  • 4
  • 5

有关transports的更多信息,请参见Transports。

7. Transport protocols

传输协议在传输之上分层,并提供身份验证和加密。
RCF支持以下传输协议:

NTLM和Kerberos传输协议只在Windows上受支持,而SSL传输协议在所有平台上都受支持。
RcfServer可以配置为需要某些传输协议:

std::vector<RCF::TransportProtocol> protocols;
protocols.push_back(RCF::Tp_Ntlm);
protocols.push_back(RCF::Tp_Kerberos);
server.setSupportedTransportProtocols(protocols);

 
 
  • 1
  • 2
  • 3
  • 4

在客户端,ClientStub::setTransportProtocol()用于配置传输协议。例如,要在客户端连接上使用NTLM协议:

RcfClient<I_HelloWorld> client( RCF::TcpEndpoint(50001) );
client.getClientStub().setTransportProtocol(RCF::Tp_Ntlm);
client.Print("Hello World");

 
 
  • 1
  • 2
  • 3

在本例中,客户机将使用登录用户的隐式凭证向服务器进行身份验证,并使用NTLM协议加密其连接。

要提供显式凭据,请使用ClientStub::setUsername()和ClientStub::setPassword():

RcfClient<I_HelloWorld> client( RCF::TcpEndpoint(50001) );
client.getClientStub().setTransportProtocol(RCF::Tp_Ntlm);
client.getClientStub().setUsername("SomeDomain\\Joe");
client.getClientStub().setPassword("JoesPassword");
client.Print("Hello World");

 
 
  • 1
  • 2
  • 3
  • 4
  • 5

Kerberos协议也可以类似地配置。Kerberos协议要求客户机提供服务器的服务主体名称(SPN)。为此,可以调用ClientStub::setKerberosSpn():

RcfClient<I_HelloWorld> client( RCF::TcpEndpoint(50001) );
client.getClientStub().setTransportProtocol(RCF::Tp_Kerberos);
client.getClientStub().setKerberosSpn("SomeDomain\\ServerAccount");
client.Print("Hello World");

 
 
  • 1
  • 2
  • 3
  • 4

如果客户端试图在不配置服务器所需的传输协议的情况下调用Print(),他们将得到一个错误:

try{
    RcfClient<I_HelloWorld> client( RCF::TcpEndpoint(50001) );
    client.Print("Hello World");
} catch(const RCF::Exception & e) {
    std::cout << "Error: " << e.getErrorString() << std::endl;
}

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
Error: Server requires one of the following transport protocols to be used: NTLM, Kerberos.

 
 
  • 1

在Print()的服务器实现中,可以检索当前会话的传输协议。如果传输协议是NTLM或Kerberos,还可以检索客户机的用户名,并模拟客户机:

class HelloWorldImpl{
public:
    void Print(const std::string & s){
        RCF::RcfSession & session = RCF::getCurrentRcfSession();
        RCF::TransportProtocol protocol = session.getTransportProtocol();
    <span class="token keyword">if</span> <span class="token punctuation">(</span> protocol <span class="token operator">==</span> RCF<span class="token operator">::</span>Tp_Ntlm <span class="token operator">||</span> protocol <span class="token operator">==</span> RCF<span class="token operator">::</span>Tp_Kerberos <span class="token punctuation">)</span><span class="token punctuation">{</span>
        std<span class="token operator">::</span>string clientUsername <span class="token operator">=</span> session<span class="token punctuation">.</span><span class="token function">getClientUsername</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        RCF<span class="token operator">::</span>SspiImpersonator <span class="token function">impersonator</span><span class="token punctuation">(</span>session<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// 现在在客户端的Windows凭据下运行。</span>
        <span class="token comment">// ...</span>

        <span class="token comment">// 在我们退出作用域(scope)时模拟(Impersonation)结束。</span>
    <span class="token punctuation">}</span>
    std<span class="token operator">::</span>cout <span class="token operator">&lt;&lt;</span> s <span class="token operator">&lt;&lt;</span> std<span class="token operator">::</span>endl<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

};

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

RCF还支持使用SSL作为传输协议。RCF提供了两种SSL实现,一种基于OpenSSL,另一种基于Windows Schannel安全包。Windows Schannel实现在Windows上自动使用,而如果在构建RCF时定义了RCF_USE_OPENSSL,则使用OpenSSL实现。

启用SSL的服务器需要配置SSL证书。证书配置的机制因使用的实现而异。下面是一个使用Schannel SSL实现的例子:

RCF::RcfServer server( RCF::TcpEndpoint(50001) );
RCF::CertificatePtr serverCertificatePtr( new RCF::PfxCertificate(
    "C:\\ServerCert.p12", 
    "Password",
    "CertificateName") );

server.setCertificate(serverCertificatePtr);
server.start();

RcfClient<I_HelloWorld> client( RCF::TcpEndpoint(50001) );
client.getClientStub().setTransportProtocol(RCF::Tp_Ssl);
client.getClientStub().setEnableSchannelCertificateValidation(“localhost”);

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

PfxCertificate用于从.pfx和.p12文件加载PKCS #12证书。RCF还提供了RCF::StoreCertificate类,用于从Windows证书存储中加载证书。
当使用基于openssl的SSL实现时,RCF::PemCertificate类用于从. PEM文件加载PEM证书。
RCF还支持远程调用的链路级压缩。压缩使用ClientStub::setEnableCompression()独立于传输协议进行配置。压缩阶段紧接在传输协议阶段之前应用。

下面是一个客户端通过HTTP代理连接到服务器的例子,使用NTLM进行身份验证和加密,并启用压缩:

RcfClient<I_HelloWorld> client( RCF::HttpEndpoint("server123.com", 80) );
client.getClientStub().setHttpProxy("proxy.mycompany.com");
client.getClientStub().setHttpProxyPort(8080);
client.getClientStub().setTransportProtocol(RCF::Tp_Ntlm);
client.getClientStub().setEnableCompression(true);

client.Print(“Hello World”);

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

有关更多信息,请参见传输协议。

8. Server-side threading

默认情况下,RcfServer使用一个线程来处理传入的远程调用,因此远程调用是连续地分派的,一个接一个。

如果您有多个客户端,并且其中一些客户端正在进行花费大量时间才能完成的调用,那么这可能会成为一个问题。为了提高这些情况下的响应能力,可以将RcfServer配置为运行多个线程并并行分派远程调用。

要配置多线程RcfServer,请使用RcfServer::setThreadPool()将线程池分配给服务器。RCF线程池可以配置为使用固定数量的线程:

RCF::RcfServer server( RCF::TcpEndpoint(50001) );
// 具有固定线程数(5)的线程池。
RCF::ThreadPoolPtr tpPtr( new RCF::ThreadPool(5) );
server.setThreadPool(tpPtr);
server.start();

 
 
  • 1
  • 2
  • 3
  • 4
  • 5

,或随服务器负载变化的动态线程数:

RCF::RcfServer server( RCF::TcpEndpoint(50001) );
// 具有不同数量线程(1到25个)的线程池。
RCF::ThreadPoolPtr tpPtr( new RCF::ThreadPool(1, 25) );
server.setThreadPool(tpPtr);
server.start();

 
 
  • 1
  • 2
  • 3
  • 4
  • 5

通过RcfServer::setThreadPool()配置的线程池在该RcfServer的所有传输中共享。也可以使用I_ServerTransport::setThreadPool()为单个传输配置线程池:

RCF::RcfServer server;
RCF::ServerTransport & tcpTransport = server.addEndpoint(RCF::TcpEndpoint(50001));
RCF::ServerTransport & pipeTransport = server.addEndpoint(RCF::Win32NamedPipeEndpoint("MyPipe"));

// 最多有5个线程来服务TCP客户机的线程池。
RCF::ThreadPoolPtr tcpThreadPoolPtr( new RCF::ThreadPool(1, 5) );
tcpTransport.setThreadPool(tcpThreadPoolPtr);

// 使用单线程的线程池来服务命名管道客户端。
RCF::ThreadPoolPtr pipeThreadPoolPtr( new RCF::ThreadPool(1) );
pipeTransport.setThreadPool(pipeThreadPoolPtr);

server.start();

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

9. Asynchronous remote calls

RCF支持客户端asynchronous remote call invocation和服务器端asynchronous remote call dispatching。

9.1 Asynchronous remote call invocation

在客户端,异步远程调用允许您避免阻塞正在进行远程调用的线程。异步远程调用在后台线程上完成,调用线程将在稍后调用完成时得到通知。

使用RCF::Future<>模板在RCF中实现异步远程调用。下面是一个等待异步调用完成的简单例子:

HelloWorldImpl helloWorld;
RCF::RcfServer server( RCF::TcpEndpoint(50001) );
server.bind<I_HelloWorld>(helloWorld);
server.start();

RcfClient<I_HelloWorld> client( RCF::TcpEndpoint(50001) );
RCF::Future<int> fRet;

// Asynchronous remote call.
fRet = client.Print(“Hello World”);

// Wait for the call to complete.
while (!fRet.ready()) RCF::sleepMs(1000);

// Check for errors.
std::auto_ptr<RCF::Exception> ePtr = client.getClientStub().getAsyncException();
if (ePtr.get()){
// Error handling.
// …
}else{
int howManyCharsPrinted = *fRet;
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

远程调用是异步执行的,如果任何参数或返回值的类型是RCF::Future<>,或者如果RCF::AsyncOneway或RCF::AsyncTwoway指定为调用语义,则执行远程调用。一旦调用完成,RCF::Future<>实例就可以取消引用以检索返回值。如果调用完成时带有错误,则可以通过调用RCF::ClientStub::getAsyncException()检索错误。如果试图取消对相关RCF::Future<>实例的引用,也会抛出该错误。

不需要在调用线程上等待结果,我们可以为远程调用分配一个完成回调:

void onPrintCompleted(HelloWorldPtr clientPtr);
void onWaitCompleted(HelloWorldPtr clientPtr);

void onPrintCompleted(HelloWorldPtr clientPtr){
// Print() call completed. Wait for 10 seconds.

clientPtr<span class="token operator">-</span><span class="token operator">&gt;</span><span class="token function">getClientStub</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">wait</span><span class="token punctuation">(</span>
    boost<span class="token operator">::</span><span class="token function">bind</span><span class="token punctuation">(</span><span class="token operator">&amp;</span>onWaitCompleted<span class="token punctuation">,</span> clientPtr<span class="token punctuation">)</span><span class="token punctuation">,</span>
    <span class="token number">10</span><span class="token operator">*</span><span class="token number">1000</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

}

void onWaitCompleted(HelloWorldPtr clientPtr){
// 10 second wait completed. Make another Print() call.

clientPtr<span class="token operator">-</span><span class="token operator">&gt;</span><span class="token function">Print</span><span class="token punctuation">(</span> 
    RCF<span class="token operator">::</span><span class="token function">AsyncTwoway</span><span class="token punctuation">(</span> boost<span class="token operator">::</span><span class="token function">bind</span><span class="token punctuation">(</span>onPrintCompleted<span class="token punctuation">,</span> clientPtr<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span> 
    <span class="token string">"Hello World"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
// Addresses to 50 servers.
std::vector<RCF::TcpEndpoint> servers(50);
// ...

// 创建到每个服务器的连接,并进行第一次调用。
std::vector<HelloWorldPtr> clients;
for (std::size_t i=0; i<50; ++i){
HelloWorldPtr clientPtr( new RcfClient<I_HelloWorld>(servers[i]) );
clients.push_back(clientPtr);

<span class="token comment">// Asynchronous remote call, with completion callback.</span>
clientPtr<span class="token operator">-</span><span class="token operator">&gt;</span><span class="token function">Print</span><span class="token punctuation">(</span> 
    RCF<span class="token operator">::</span><span class="token function">AsyncTwoway</span><span class="token punctuation">(</span> boost<span class="token operator">::</span><span class="token function">bind</span><span class="token punctuation">(</span><span class="token operator">&amp;</span>onPrintCompleted<span class="token punctuation">,</span> clientPtr<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span> 
    <span class="token string">"Hello World"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

}
// 所有50台服务器现在每10秒调用一次。
// …

// 离开作用域时,所有客户机都将自动销毁。任何正在进行的远程调用都会自动取消。

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

与使用同步远程调用阻塞50个线程不同,所有50个连接都由一个线程管理。对50台服务器的远程调用序列都在后台RCF线程上处理,当主线程离开作用域时,连接将自动销毁。

9.2 Asynchronous remote call dispatching

RCF还支持服务器端异步远程调用调度。当远程调用到达RcfServer时,它由服务器线程池中的一个线程处理。要在另一个线程上异步处理调用,可以使用RCF::RemoteCallContext<>模板来捕获远程调用的服务器端上下文,并对其进行排队,以便稍后处理。

下面是在服务器端代码中使用RemoteCallContext<>的示例。我们不是响应HelloWorldImpl::Print()中的Print()调用,而是将远程调用上下文传递给后台线程,以便每秒批量处理一次。后台线程使用RemoteCallContext::parameters()访问每个远程调用的参数,并使用RemoteCallContext::commit()将远程调用响应发送回客户机。

#include <RCF/RemoteCallContext.hpp>

RCF_BEGIN(I_HelloWorld, “I_HelloWorld”)
RCF_METHOD_R1(int, Print, const std::string &)
RCF_END(I_HelloWorld)

// I_HelloWorld servant object
class HelloWorldImpl{
public:
typedef RCF::RemoteCallContext<int, const std::string &> PrintCall;

<span class="token keyword">int</span> <span class="token function">Print</span><span class="token punctuation">(</span><span class="token keyword">const</span> std<span class="token operator">::</span>string <span class="token operator">&amp;</span> s<span class="token punctuation">)</span><span class="token punctuation">{</span>
    <span class="token comment">// Capture the remote call context and queue it in mPrintCalls.</span>
    RCF<span class="token operator">::</span>Lock <span class="token function">lock</span><span class="token punctuation">(</span>mPrintCallsMutex<span class="token punctuation">)</span><span class="token punctuation">;</span>
    mPrintCalls<span class="token punctuation">.</span><span class="token function">push_back</span><span class="token punctuation">(</span> <span class="token function">PrintCall</span><span class="token punctuation">(</span>RCF<span class="token operator">::</span><span class="token function">getCurrentRcfSession</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token comment">// Dummy return value.</span>
    <span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token function">HelloWorldImpl</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
    <span class="token comment">// Start the asynchronous printing thread.</span>
    mStopFlag <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
    mPrintThreadPtr<span class="token punctuation">.</span><span class="token function">reset</span><span class="token punctuation">(</span> <span class="token keyword">new</span> RCF<span class="token operator">::</span><span class="token function">Thread</span><span class="token punctuation">(</span> boost<span class="token operator">::</span><span class="token function">bind</span><span class="token punctuation">(</span>
        <span class="token operator">&amp;</span>HelloWorldImpl<span class="token operator">::</span>processPrintCalls<span class="token punctuation">,</span> 
        <span class="token keyword">this</span><span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token operator">~</span><span class="token function">HelloWorldImpl</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
    <span class="token comment">// Stop the asynchronous printing thread.</span>
    mStopFlag <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span>
    mPrintThreadPtr<span class="token operator">-</span><span class="token operator">&gt;</span><span class="token function">join</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

private:
// Queue of remote calls.
RCF::Mutex mPrintCallsMutex;
std::deque<PrintCall> mPrintCalls;

<span class="token comment">// Asynchronous printing thread.</span>
RCF<span class="token operator">::</span>ThreadPtr          mPrintThreadPtr<span class="token punctuation">;</span>
<span class="token keyword">volatile</span> <span class="token keyword">bool</span>           mStopFlag<span class="token punctuation">;</span>

<span class="token keyword">void</span> <span class="token function">processPrintCalls</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
    <span class="token comment">// Once a second, process all queued Print() calls.</span>
    <span class="token keyword">while</span> <span class="token punctuation">(</span><span class="token operator">!</span>mStopFlag<span class="token punctuation">)</span><span class="token punctuation">{</span>
        <span class="token function">Sleep</span><span class="token punctuation">(</span><span class="token number">1000</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// Retrieve all queued print calls.</span>
        std<span class="token operator">::</span>deque<span class="token operator">&lt;</span>PrintCall<span class="token operator">&gt;</span> printCalls<span class="token punctuation">;</span><span class="token punctuation">{</span>
            RCF<span class="token operator">::</span>Lock <span class="token function">lock</span><span class="token punctuation">(</span>mPrintCallsMutex<span class="token punctuation">)</span><span class="token punctuation">;</span>
            printCalls<span class="token punctuation">.</span><span class="token function">swap</span><span class="token punctuation">(</span>mPrintCalls<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>

        <span class="token comment">// Process them.</span>
        <span class="token keyword">for</span> <span class="token punctuation">(</span>std<span class="token operator">::</span>size_t i<span class="token operator">=</span><span class="token number">0</span><span class="token punctuation">;</span> i<span class="token operator">&lt;</span>printCalls<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token operator">++</span>i<span class="token punctuation">)</span><span class="token punctuation">{</span>
            PrintCall <span class="token operator">&amp;</span> printCall <span class="token operator">=</span> printCalls<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">;</span>
            <span class="token keyword">const</span> std<span class="token operator">::</span>string <span class="token operator">&amp;</span> stringToPrint <span class="token operator">=</span> printCall<span class="token punctuation">.</span><span class="token function">parameters</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>a1<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            std<span class="token operator">::</span>cout <span class="token operator">&lt;&lt;</span> <span class="token string">"I_HelloWorld service: "</span> <span class="token operator">&lt;&lt;</span> stringToPrint <span class="token operator">&lt;&lt;</span> std<span class="token operator">::</span>endl<span class="token punctuation">;</span>
            printCall<span class="token punctuation">.</span><span class="token function">parameters</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>r<span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span> stringToPrint<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
            printCall<span class="token punctuation">.</span><span class="token function">commit</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

};

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63

客户端代码不变:

int main()
{
    RCF::RcfInitDeinit rcfInit;
HelloWorldImpl helloWorld<span class="token punctuation">;</span>
RCF<span class="token operator">::</span>RcfServer <span class="token function">server</span><span class="token punctuation">(</span> RCF<span class="token operator">::</span><span class="token function">TcpEndpoint</span><span class="token punctuation">(</span><span class="token number">50001</span><span class="token punctuation">)</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
server<span class="token punctuation">.</span>bind<span class="token operator">&lt;</span>I_HelloWorld<span class="token operator">&gt;</span><span class="token punctuation">(</span>helloWorld<span class="token punctuation">)</span><span class="token punctuation">;</span>
server<span class="token punctuation">.</span><span class="token function">start</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

RcfClient<span class="token operator">&lt;</span>I_HelloWorld<span class="token operator">&gt;</span> <span class="token function">client</span><span class="token punctuation">(</span> RCF<span class="token operator">::</span><span class="token function">TcpEndpoint</span><span class="token punctuation">(</span><span class="token number">50001</span><span class="token punctuation">)</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> charsPrinted <span class="token operator">=</span> client<span class="token punctuation">.</span><span class="token function">Print</span><span class="token punctuation">(</span><span class="token string">"Hello World"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

有关更多信息,请参见异步远程调用。

10. Publish/subscribe

RCF使设置发布/订阅提要变得很容易。例如,这里有一个发布者每秒钟发布一次“Hello World”:

RCF::RcfServer publishingServer( RCF::TcpEndpoint(50001) );
publishingServer.start();
// Start publishing.
typedef boost::shared_ptr< RCF::Publisher<I_HelloWorld> > HelloWorldPublisherPtr;
HelloWorldPublisherPtr pubPtr = publishingServer.createPublisher<I_HelloWorld>();

while (shouldContinue()){
Sleep(1000);
// Publish a Print() call to all currently connected subscribers.
pubPtr->publish().Print(“Hello World”);
}
// Close the publisher.
pubPtr->close();

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

要创建一个对发布者的订阅:

// Start a subscriber.
RCF::RcfServer subscriptionServer(( RCF::TcpEndpoint() ));
subscriptionServer.start();

HelloWorldImpl helloWorld;

RCF::SubscriptionPtr subPtr = subscriptionServer.createSubscription<I_HelloWorld>(
helloWorld,
RCF::TcpEndpoint(50001));

// At this point Print() will be called on the helloWorld object once a second.
// …

// Close the subscription.
subPtr->close();

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

发布者发出的每个调用都作为单向调用发送给所有订阅者。

有关发布/订阅消息传递的更多信息,请参见发布/订阅。

11. Callback connections

到目前为止,我们已经看到客户端对服务器进行远程调用。一旦客户端建立了连接,服务器也可以对客户端进行远程调用。为此,客户机启动自己的RcfServer,并调用RcfServer::createCallbackConnection():

// Client-side
int main(){
    RCF::RcfInitDeinit rcfInit; 
    // Client needs a RcfServer to accept callback connections.
    RCF::RcfServer callbackServer(( RCF::TcpEndpoint() ));
    HelloWorldImpl helloWorld;
    callbackServer.bind<I_HelloWorld>(helloWorld);
    callbackServer.start();
<span class="token comment">// Establish client connection to server.</span>
RcfClient<span class="token operator">&lt;</span>I_HelloWorld<span class="token operator">&gt;</span> <span class="token function">client</span><span class="token punctuation">(</span> RCF<span class="token operator">::</span><span class="token function">TcpEndpoint</span><span class="token punctuation">(</span><span class="token number">50001</span><span class="token punctuation">)</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// Create the callback connection.</span>
RCF<span class="token operator">::</span><span class="token function">createCallbackConnection</span><span class="token punctuation">(</span>client<span class="token punctuation">,</span> callbackServer<span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// Server can now call Print() on the helloWorld object.</span>
<span class="token comment">// ...</span>
<span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

在服务器端,RcfServer::setCallbackConnectionCb()用于在客户端创建回调连接后控制回调连接:

// Server-side
typedef boost::shared_ptr< RcfClient<I_HelloWorld> >    HelloWorldPtr;
RCF::Mutex                                              gCallbackClientsMutex;
std::vector< HelloWorldPtr >                            gCallbackClients;

void onCallbackConnectionCreated(
RCF::RcfSessionPtr sessionPtr,
RCF::ClientTransportAutoPtr transportAutoPtr){

<span class="token keyword">typedef</span> boost<span class="token operator">::</span>shared_ptr<span class="token operator">&lt;</span> RcfClient<span class="token operator">&lt;</span>I_HelloWorld<span class="token operator">&gt;</span> <span class="token operator">&gt;</span> HelloWorldPtr<span class="token punctuation">;</span>
HelloWorldPtr <span class="token function">helloWorldPtr</span><span class="token punctuation">(</span> <span class="token keyword">new</span> RcfClient<span class="token operator">&lt;</span>I_HelloWorld<span class="token operator">&gt;</span><span class="token punctuation">(</span>transportAutoPtr<span class="token punctuation">)</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
RCF<span class="token operator">::</span>Lock <span class="token function">lock</span><span class="token punctuation">(</span>gCallbackClientsMutex<span class="token punctuation">)</span><span class="token punctuation">;</span>
gCallbackClients<span class="token punctuation">.</span><span class="token function">push_back</span><span class="token punctuation">(</span> helloWorldPtr <span class="token punctuation">)</span><span class="token punctuation">;</span>

}

int main(){
RCF::RcfInitDeinit rcfInit;
RCF::RcfServer server( RCF::TcpEndpoint(50001) );

server<span class="token punctuation">.</span><span class="token function">setOnCallbackConnectionCreated</span><span class="token punctuation">(</span> 
    boost<span class="token operator">::</span><span class="token function">bind</span><span class="token punctuation">(</span><span class="token operator">&amp;</span>onCallbackConnectionCreated<span class="token punctuation">,</span> _1<span class="token punctuation">,</span> _2<span class="token punctuation">)</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
server<span class="token punctuation">.</span><span class="token function">start</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// Wait for clients to create callback connections.</span>
<span class="token comment">// ...</span>

<span class="token comment">// Retrieve all created callback connections.</span>
std<span class="token operator">::</span>vector<span class="token operator">&lt;</span>HelloWorldPtr<span class="token operator">&gt;</span> clients<span class="token punctuation">;</span><span class="token punctuation">{</span>
    RCF<span class="token operator">::</span>Lock <span class="token function">lock</span><span class="token punctuation">(</span>gCallbackClientsMutex<span class="token punctuation">)</span><span class="token punctuation">;</span>
    clients<span class="token punctuation">.</span><span class="token function">swap</span><span class="token punctuation">(</span>gCallbackClients<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token comment">// Call Print() on them.</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span>std<span class="token operator">::</span>size_t i<span class="token operator">=</span><span class="token number">0</span><span class="token punctuation">;</span> i<span class="token operator">&lt;</span>clients<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token operator">++</span>i<span class="token punctuation">)</span><span class="token punctuation">{</span>
    HelloWorldPtr clientPtr <span class="token operator">=</span> clients<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">;</span>
    clientPtr<span class="token operator">-</span><span class="token operator">&gt;</span><span class="token function">Print</span><span class="token punctuation">(</span><span class="token string">"Hello World"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40

回调连接的功能与常规连接一样,只是回调连接不能重新连接。如果回调连接丢失,客户机将需要重新连接并调用RCF::createCallbackConnection(),以重新建立连接。

有关回调连接的更多信息,请参见回调连接。

12. File transfers

文件下载和上传在分布式系统中很常见。RCF通过RCF::FileDownload和RCF::FileUpload类为文件传输提供内置支持。RCF::FileDownload和RCF::FileUpload用作远程方法参数,以实现文件传输作为远程调用的一部分。

在服务器端,默认情况下禁用文件传输功能,需要显式启用:

HelloWorldImpl helloWorld;
RCF::RcfServer server( RCF::TcpEndpoint(50001) );
server.bind<I_HelloWorld>(helloWorld);
server.start();

 
 
  • 1
  • 2
  • 3
  • 4

这里我们实现了一个PrintAndDownload()方法,它允许客户端下载文件:

RCF_BEGIN(I_HelloWorld, "I_HelloWorld")
    RCF_METHOD_V1(void, Print, const std::string &)
    RCF_METHOD_V2(void, PrintAndDownload, const std::string &, RCF::FileDownload)
RCF_END(I_HelloWorld)

class HelloWorldImpl{
public:
void Print(const std::string & s){
std::cout << "I_HelloWorld service: " << s << std::endl;
}

<span class="token keyword">void</span> <span class="token function">PrintAndDownload</span><span class="token punctuation">(</span><span class="token keyword">const</span> std<span class="token operator">::</span>string <span class="token operator">&amp;</span> s<span class="token punctuation">,</span> RCF<span class="token operator">::</span>FileDownload fileDownload<span class="token punctuation">)</span><span class="token punctuation">{</span>
    std<span class="token operator">::</span>cout <span class="token operator">&lt;&lt;</span> <span class="token string">"I_HelloWorld service: "</span> <span class="token operator">&lt;&lt;</span> s <span class="token operator">&lt;&lt;</span> std<span class="token operator">::</span>endl<span class="token punctuation">;</span>
    fileDownload <span class="token operator">=</span> RCF<span class="token operator">::</span><span class="token function">FileDownload</span><span class="token punctuation">(</span><span class="token string">"path/to/download"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

};

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

,这可以被调用像这样:

RcfClient<I_HelloWorld> client( RCF::TcpEndpoint(50001) );
RCF::FileDownload fileDownload("path/to/download/to");
client.PrintAndDownload("Hello World", fileDownload);

std::string pathToDownload = fileDownload.getLocalPath();
RCF::FileManifest & downloadManifest = fileDownload.getManifest();
std::cout << "Client-local path to upload: " << pathToDownload << std::endl;
std::cout << "Number of files uploaded: " << downloadManifest.mFiles.size() << std::endl;

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

这里我们实现了一个PrintAndUpload()方法,它允许客户端上传文件:

RCF_BEGIN(I_HelloWorld, "I_HelloWorld")
    RCF_METHOD_V1(void, Print, const std::string &)
    RCF_METHOD_V2(void, PrintAndUpload, const std::string &, RCF::FileUpload)
RCF_END(I_HelloWorld)

class HelloWorldImpl{
public:
void Print(const std::string & s){
std::cout << "I_HelloWorld service: " << s << std::endl;
}

<span class="token keyword">void</span> <span class="token function">PrintAndUpload</span><span class="token punctuation">(</span><span class="token keyword">const</span> std<span class="token operator">::</span>string <span class="token operator">&amp;</span> s<span class="token punctuation">,</span> RCF<span class="token operator">::</span>FileUpload fileUpload<span class="token punctuation">)</span><span class="token punctuation">{</span>
    std<span class="token operator">::</span>cout <span class="token operator">&lt;&lt;</span> <span class="token string">"I_HelloWorld service: "</span> <span class="token operator">&lt;&lt;</span> s <span class="token operator">&lt;&lt;</span> std<span class="token operator">::</span>endl<span class="token punctuation">;</span>
    std<span class="token operator">::</span>string pathToUpload <span class="token operator">=</span> fileUpload<span class="token punctuation">.</span><span class="token function">getLocalPath</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    RCF<span class="token operator">::</span>FileManifest <span class="token operator">&amp;</span> uploadManifest <span class="token operator">=</span> fileUpload<span class="token punctuation">.</span><span class="token function">getManifest</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    std<span class="token operator">::</span>cout <span class="token operator">&lt;&lt;</span> <span class="token string">"Server-local path to upload: "</span> <span class="token operator">&lt;&lt;</span> pathToUpload <span class="token operator">&lt;&lt;</span> std<span class="token operator">::</span>endl<span class="token punctuation">;</span>
    std<span class="token operator">::</span>cout <span class="token operator">&lt;&lt;</span> <span class="token string">"Number of files uploaded: "</span> <span class="token operator">&lt;&lt;</span> uploadManifest<span class="token punctuation">.</span>mFiles<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">&lt;&lt;</span> std<span class="token operator">::</span>endl<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

};

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

,这可以被调用像这样:

// Upload files to server.
RcfClient<I_HelloWorld> client( RCF::TcpEndpoint(50001) );
RCF::FileUpload fileUpload("path/to/files");
client.PrintAndUpload("Hello World", fileUpload);

 
 
  • 1
  • 2
  • 3
  • 4

可以监视、暂停、恢复和取消文件传输,还可以对进出给定服务器的文件传输应用带宽节流。
有关更多信息,请参见文件传输。

13. Protocol Buffers

RCF提供了与Protocol Buffers的本地集成。Protocol Buffers编译器生成的类可用于RCF接口,并通过相关 Protocol Buffers函数执行序列化和反序列化。
例如,在以下Protobuf接口上运行protoc编译器:

// Person.proto
message Person {
    required int32 id = 1;
    required string name = 2;
    optional string email = 3;
}

message PbEmpty {
optional string log = 1;
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
protoc Person.proto --cpp_out=.

 
 
  • 1

,生成c++类Person,在Person.pb.h中定义。
通过包括Person.pb.h,我们可以将Person实例发送到Print()函数:

#include <../test/protobuf/messages/cpp/Person.pb.h>

RCF_BEGIN(I_HelloWorld, “I_HelloWorld”)
RCF_METHOD_V1(void, Print, const std::string &)
RCF_METHOD_V1(void, Print, const Person &)
RCF_END(I_HelloWorld)

class HelloWorldImpl{
public:
void Print(const std::string & s){
std::cout << s << std::endl;
}

<span class="token keyword">void</span> <span class="token function">Print</span><span class="token punctuation">(</span><span class="token keyword">const</span> Person <span class="token operator">&amp;</span> person<span class="token punctuation">)</span><span class="token punctuation">{</span>
    std<span class="token operator">::</span>cout <span class="token operator">&lt;&lt;</span> <span class="token string">"Person name: "</span> <span class="token operator">&lt;&lt;</span> person<span class="token punctuation">.</span><span class="token function">name</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    std<span class="token operator">::</span>cout <span class="token operator">&lt;&lt;</span> <span class="token string">"Person email: "</span> <span class="token operator">&lt;&lt;</span> person<span class="token punctuation">.</span><span class="token function">email</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    std<span class="token operator">::</span>cout <span class="token operator">&lt;&lt;</span> <span class="token string">"Person id: "</span> <span class="token operator">&lt;&lt;</span> person<span class="token punctuation">.</span><span class="token function">id</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

};

int main(){
RCF::RcfInitDeinit rcfInit;
HelloWorldImpl helloWorld;
RCF::RcfServer server( RCF::TcpEndpoint(50001) );
server.bind<I_HelloWorld>(helloWorld);
server.start();

RcfClient<span class="token operator">&lt;</span>I_HelloWorld<span class="token operator">&gt;</span> <span class="token function">client</span><span class="token punctuation">(</span> RCF<span class="token operator">::</span><span class="token function">TcpEndpoint</span><span class="token punctuation">(</span><span class="token number">50001</span><span class="token punctuation">)</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>

Person person<span class="token punctuation">;</span>
person<span class="token punctuation">.</span><span class="token function">set_name</span><span class="token punctuation">(</span><span class="token string">"Bob"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
person<span class="token punctuation">.</span><span class="token function">set_email</span><span class="token punctuation">(</span><span class="token string">"bob@acme.com"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
person<span class="token punctuation">.</span><span class="token function">set_id</span><span class="token punctuation">(</span><span class="token number">123</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
client<span class="token punctuation">.</span><span class="token function">Print</span><span class="token punctuation">(</span>person<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

有关Protocol Buffers支持的更多信息,请参见Protocol Buffers

14. JSON-RPC

RCF提供了一个内置的JSON-RPC服务器,允许从JSON-RPC客户机访问c++服务器功能,比如web页面上的Javascript代码。RCF支持HTTP和HTTPS上的JSON-RPC。
RCF使用JSON Spirit库读写JSON消息。您需要单独下载这个库,并在构建RCF时定义RCF_USE_JSON,以启用JSON-RPC支持(参见附录 - Building)。
要配置JSON-RPC端点,请在相关服务器传输上调用I_ServerTransport::setRpcProtocol()。要将服务对象公开给JSON-RPC客户机,请使用RcfServer::bindJsonRpc()。

下面是一个RCF服务器使用多个传输来同时接受RCF请求和JSON-RPC请求的例子:

RCF_BEGIN(I_HelloWorld, "I_HelloWorld")
    RCF_METHOD_V1(void, Print, const std::string &)
RCF_END(I_HelloWorld)

class HelloWorldImpl{
public:
void Print(const std::string & s){
std::cout << "I_HelloWorld service: " << s << std::endl;
}

<span class="token keyword">void</span> <span class="token function">JsonPrint</span><span class="token punctuation">(</span>
    <span class="token keyword">const</span> RCF<span class="token operator">::</span>JsonRpcRequest <span class="token operator">&amp;</span> request<span class="token punctuation">,</span> 
    RCF<span class="token operator">::</span>JsonRpcResponse <span class="token operator">&amp;</span> response<span class="token punctuation">)</span><span class="token punctuation">{</span>
    
    <span class="token comment">// Print out all the strings passed in, and return the number of</span>
    <span class="token comment">// characters printed.</span>
    <span class="token keyword">int</span> charsPrinted <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>

    <span class="token keyword">const</span> json_spirit<span class="token operator">::</span>Array <span class="token operator">&amp;</span> params <span class="token operator">=</span> request<span class="token punctuation">.</span><span class="token function">getJsonParams</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">for</span> <span class="token punctuation">(</span>std<span class="token operator">::</span>size_t i<span class="token operator">=</span><span class="token number">0</span><span class="token punctuation">;</span> i<span class="token operator">&lt;</span>params<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token operator">++</span>i<span class="token punctuation">)</span><span class="token punctuation">{</span>
        <span class="token keyword">const</span> std<span class="token operator">::</span>string <span class="token operator">&amp;</span> s <span class="token operator">=</span> params<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">get_str</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        std<span class="token operator">::</span>cout <span class="token operator">&lt;&lt;</span> <span class="token string">"I_HelloWorld service: "</span> <span class="token operator">&lt;&lt;</span> s <span class="token operator">&lt;&lt;</span> std<span class="token operator">::</span>endl<span class="token punctuation">;</span>
        charsPrinted <span class="token operator">+</span><span class="token operator">=</span> s<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    <span class="token comment">// Return number of characters printed.</span>
    json_spirit<span class="token operator">::</span>mObject <span class="token operator">&amp;</span> responseObj <span class="token operator">=</span> response<span class="token punctuation">.</span><span class="token function">getJsonResponse</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    responseObj<span class="token punctuation">[</span><span class="token string">"result"</span><span class="token punctuation">]</span> <span class="token operator">=</span> charsPrinted<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

};

int main(){
RCF::RcfInitDeinit rcfInit;
RCF::RcfServer server;

<span class="token comment">// Accept RCF client requests on port 50001.</span>
HelloWorldImpl helloWorld<span class="token punctuation">;</span>
server<span class="token punctuation">.</span>bind<span class="token operator">&lt;</span>I_HelloWorld<span class="token operator">&gt;</span><span class="token punctuation">(</span>helloWorld<span class="token punctuation">)</span><span class="token punctuation">;</span>
server<span class="token punctuation">.</span><span class="token function">addEndpoint</span><span class="token punctuation">(</span> RCF<span class="token operator">::</span><span class="token function">TcpEndpoint</span><span class="token punctuation">(</span><span class="token number">50001</span><span class="token punctuation">)</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// Accept JSON-RPC requests over HTTP on port 80.</span>
server<span class="token punctuation">.</span><span class="token function">bindJsonRpc</span><span class="token punctuation">(</span>
    boost<span class="token operator">::</span><span class="token function">bind</span><span class="token punctuation">(</span><span class="token operator">&amp;</span>HelloWorldImpl<span class="token operator">::</span>JsonPrint<span class="token punctuation">,</span> <span class="token operator">&amp;</span>helloWorld<span class="token punctuation">,</span> _1<span class="token punctuation">,</span> _2<span class="token punctuation">)</span><span class="token punctuation">,</span> 
    <span class="token string">"JsonPrint"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

server<span class="token punctuation">.</span><span class="token function">addEndpoint</span><span class="token punctuation">(</span> RCF<span class="token operator">::</span><span class="token function">HttpEndpoint</span><span class="token punctuation">(</span><span class="token number">80</span><span class="token punctuation">)</span> <span class="token punctuation">)</span>
    <span class="token punctuation">.</span><span class="token function">setRpcProtocol</span><span class="token punctuation">(</span>RCF<span class="token operator">::</span>Rp_JsonRpc<span class="token punctuation">)</span><span class="token punctuation">;</span>

server<span class="token punctuation">.</span><span class="token function">start</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// RCF clients can call Print() on port 50001.</span>
<span class="token comment">// ...</span>

<span class="token comment">// JSON-RPC clients can call JsonPrint() over HTTP on port 80.</span>
<span class="token comment">// ...</span>
<span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56

有关JSON-RPC服务器的更多信息,请参见JSON-RPC。

                                </div>
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值