附录 - 常见问题解答

1. Building

1.1 Why is my program trying to link to a Boost library?(为什么我的程序试图链接到一个Boost库?)

如果您已经定义了RCF_USE_BOOST_SERIALIZATION,那么RCF将需要链接到Boost.Serialization库。
如果您已经定义了RCF_USE_BOOST_FILESYSTEM,那么RCF将需要链接到Boost.FilesystemBoost.System库。
RCF不链接到任何其他Boost库。
Boost库具有自动链接功能,这也许会导致链接器查找要链接的错误文件。您可以定义BOOST_ALL_NO_LIB,然后显式地告诉链接器要链接到哪些文件。

1.2 Can I compile RCF into a DLL?(我可以把RCF编译成一个DLL吗?)

是的。要从一个DLL中导出RCF函数,需要定义RCF_BUILD_DLL

1.3 Why do I sometimes get compiler errors when I include <windows.h> before RCF headers?(为什么我有时会得到编译器错误当我在RCF头文件之前include <windows.h>?)

由于Windows平台头文件<windows.h> 和<winsock2.h>的头文件排序问题。包括<窗口。在默认情况下,Including <windows.h>将包含一个较老版本的Winsock,因此不可能随后include <winsock2.h>在同一个转换单元。
这个问题最简单的解决方法是在including <windows.h>之前定义WIN32_LEAN_AND_MEAN

1.4 Does RCF compile warning free on level 4 on Visual C++?(RCF在Visual C++的第4级的编译警告是否有影响?)

是的,如果以下警告被禁用:

C4510 'class' : default constructor could not be generated
C4511 'class' : copy constructor could not be generated
C4512 'class' : assignment operator could not be generated
C4127 conditional expression is constant
1.5 Can I run RCF on platform XYZ?(我可以在XYZ平台上运行RCF吗?)

可能,但是您可能需要自己对RCF做一些小的修改,以适应平台特定的问题,比如要包含哪些平台头文件。

1.6 Why do I get linker errors?(为什么会出现链接器错误?)

在Windows上,如果使用TCP transports,则需要链接到ws2_32.lib。在*nix平台上,需要链接到libnsllibsocket等库。

1.7 Does RCF support Visual C++ 6 (Visual Studio 98) ?(RCF是否支持Visual c++ 6 (Visual Studio 98) ?)

不支持。RCF 1.3.1是最后一个支持Visual c++ 6的RCF版本。

1.8 Does RCF support 64 bit compilers?(RCF支持64位编译器吗?)

支持

1.9 Does RCF support Unicode builds on Windows?(RCF是否支持Windows上的Unicode构建?)

支持

1.10 Why do I get duplicate symbol linker errors for my external serialization functions?(为什么外部serialization函数会出现重复符号的链接器错误?)

如果在一个头文件中定义了外部serialization函数,而不使用inline修饰符,并将头文件包含在两个或多个源文件中,则会得到关于重复符号的链接器错误。解决方案是添加一个inline修饰符:

// X.hpp
inline void serialize(SF::Archive & ar, X & x){
    ...
}

,或在头文件中声明序列化函数并在源文件中定义它:

// X.hpp
void serialize(SF::Archive & ar, X & x);
// X.cpp
void serialize(SF::Archive & ar, X & x){
    ...
}
1.11 How do I reduce build times for my application?(如何减少应用程序的构建时间?)

如果您将RCF头文件包含到您自己常用的应用程序头文件中,您可能会注意到构建时间的增加,因为编译器将对每个包含RCF头文件的源文件解析RCF头文件一次。
您应该只在需要时包含RCF头文件 —— 换句话说,只将它们包含到使用RCF功能的源文件中。在应用程序头文件中,能够使用前置声明,而不是包含相应的头文件。
例如,如果您定义了一个类X和一个RcfClient<>成员,您可以前置声明RcfClient<>,然后对于这个成员使用一个指针:

// X.h
template<typename T>
class RcfClient;

class SomeInterface;
typedef RcfClient<SomeInterface> MyRcfClient;
typedef boost::shared_ptr<MyRcfClient> MyRcfClientPtr;

class RcfServer;
typedef boost::shared_ptr<RcfServer> RcfServerPtr;

// Application specific class that holds a RcfClient and a RcfServer.
class X{  
    X();
    MyRcfClientPtr mClientPtr;
    RcfServerPtr mServerPtr;
};
// X.cpp
#include "X.h"
#include <RCF/RcfClient.hpp>
#include <RCF/RcfServer.hpp>

X::X() : 
    mClientPtr( new RcfClient<SomeInterface>(...) ), 
    mRcfServerPtr( new RcfServer(...) ) 
{}

然后,您可以在应用程序的任何地方包含X.h,而不需要包含任何RCF头。

2. Platforms

2.1 Why do I run out of socket handles on Windows XP?(为什么我用完了Windows XP上的套接字句柄?)

无论何时建立一个传出TCP连接,都必须为连接分配一个本地端口号。在Windows XP中,这些本地端口(有时称为临时端口)默认是从大约4000个端口号的范围分配的。
如果您使用TCP端点创建许多RcfClient<>对象,您最终将耗尽可用端口,因为在连接关闭后,Windows会占用它们一小段时间。
您应该尽可能少地使用TCP连接(使用相同的RcfClient<>对象,而不是创建新连接)。Windows XP上还有一些注册表设置可以缓解这个问题。找到以下键:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters
,并设置
TcpNumConnections = 0x800, MaxUserPort = 65534
重新启动后,系统将允许扩展临时端口的范围。

2.2 Why does my leak detector think there is a leak in RCF?(为什么我的漏洞检测工具认为RCF有漏洞?)

可能是因为还没有执行RCF::deinit()

2.3 Is RCF’s TCP server implemenation based on I/O completion ports?(RCF的TCP服务器基于I/O completion端口实现的吗?)

在Windows上,是的。参见性能。

2.4 Does RCF support a shared memory transport?(RCF是否支持共享内存transport?)

对于本地RPC,,RCF支持由共享内存支持的命名管道transport(Win32NamedPipeEndpoint)。

2.5 Does RCF support IPv6?(RCF支持IPv6吗?)

是的 —— 请参见Transport configuration。

3. Programming

3.1 How do I keep my user interface from freezing when there’s a remote call in progress?(当远程调用正在进行时,如何防止用户接口冻结?)

要么在非UI线程上运行远程调用,要么使用progress callbacks以短时间间隔重新绘制UI。参见Progress callbacks

3.2 How do I cancel a long-running client call?(如何取消长时间运行的客户端调用?)

使用progress callbacks(参见Progress callbacks)。您可以将callback配置为在任何给定频率调用,当您想取消调用时,抛出异常。

3.3 How do I stop a server from within a remote call?(如何在远程调用中停止服务器?)

您不能在远程调用中调用RcfServer::stop(),因为stop()调用将等待所有工作线程退出,包括调用stop()的线程,从而导致死锁。如果你真的需要在远程调用中停止server,你可以启动一个新的线程:

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

RCF::RcfServer *gpServer = NULL;

class Echo{
public:
    std::string echo(const std::string &s){
        if (s == "stop"){
            // Spawn a temporary thread to stop the server.
            RCF::Thread(boost::bind(&RCF::RcfServer::stop, gpServer));
        }
        return s;
    }
};

int main(){
    Echo echo;
    RCF::RcfServer server( RCF::TcpEndpoint(0));
    server.bind<I_Echo>(echo);
    server.start();

    gpServer = &server;
    int port = server.getIpServerTransport().getPort();
    // This call will stop the server.
    RcfClient<I_Echo>(RCF::TcpEndpoint(port)).echo("stop");
    return 0;
}
3.4 How can I make remotely accessible functions private?(如何使远程访问的函数成为私有的?)

使RcfClient<>成为你的实现类的一个friend:

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

class Echo{
private:
    friend RcfClient<I_Echo>;

    std::string echo(const std::string &s){
        return s;
    }
};

3.5 How do I use a single TCP connection with several RcfClient<> instancesd?(如何使用多个RcfClient<>实例的单个TCP连接?)

您可以将网络连接从一个RcfClient<>移动到另一个RcfClient<>。参见对底层传输的访问

3.6 Can I publish/subscribe through a firewall?(我可以通过防火墙发布/订阅吗?)

是的。只要订阅者能够发起到发布者的连接,它就会接收已发布的消息。

3.7 Why can’t I use pointers in RCF interfaces?(为什么我不能在RCF接口中使用指针?)

指针不能用作RCF接口中的返回类型,因为没有安全的方法来封装它们。但是,指针可以用作远程调用的参数,其行为本质上类似于引用。

3.8 How do I start a TCP server on the first available port on my machine?(如何在机器上的第一个可用端口上启动TCP服务器?)

在传递给RcfServer构造函数的RCF::TcpEndpoint对象中指定端口号为零。启动服务器后,通过调用RcfServer::getIpServerTransport(). getport()检索端口号。

3.9 How do I forcibly disconnect a client from the server?(如何强制断开客户机与服务器的连接?)

在server实现中调用RCF::getCurrentRcfSession().disconnect()。

3.10 How do I know that a client has received a published message?(我如何知道客户端收到了已发布的消息?)

发布者不会知道,因为消息是使用oneway语义发布的。

3.11 How do I expose several servant objects having the same interface?(如何公开具有相同接口的几个服务对象?)

使用服务绑定名称。参见绑定服务对象

3.12 Why is my server only accessible from the local machine, and not across the network?(为什么我的服务器只能从本地机器访问,而不能通过网络访问?)

在传递给RcfServer的RCF::TcpEndpoint中,需要指定0.0.0.0作为IP地址,以允许客户机通过任何网络接口访问它。默认情况下使用127.0.0.1,这将限制客户机与服务器运行在同一台机器上。

3.13 At what point does a RcfClient<> object connect to the server?(一个RcfClient<>对象何时连接到服务器?)

当调用getClientStub().connect()或进行远程调用时。

3.14 Why does my program crash or assert when exiting?(为什么我的程序在退出时崩溃或断言?)

可能是因为您的程序有一个全局静态对象,其析构函数试图在RCF被取消初始化之后销毁RcfClient<>或RcfServer对象(或其他一些RCF对象)。
确保在取消初始化RCF之前销毁所有RCF对象。

3.15 How do I determine what IP address a client is connecting from?(如何确定客户机从哪个IP地址连接?)

在server实现中调用RCF::getCurrentRcfSession(). getclientaddress()

3.16 How do I serialize enums?(如何序列化枚举?)

SF将自动序列化和反序列化枚举,作为整数表示。

3.17 Can I use SF to serialize objects to and from files?(我可以使用SF来序列化对象和文件吗?)

是的,参见序列化

3.18 How do I send a file using RCF?(如何使用RCF发送一个文件?)

参见File Transfers。

3.19 How does a subscriber know if a publisher has stopped publishing?(订阅者如何知道发布者是否已停止发布?)

您可以使用断开连接通知,或轮询订阅者的连接情况。参见发布/订阅。

3.20 How can I access the internal asio::io_service used by the RCF server?(如何访问RCF服务器使用的内部asio::io_service ?)

您可以调用AsioServerTransport::getIoService()

#include <RCF/AsioServerTransport.hpp>

RCF::RcfServer server( ... );
RCF::I_ServerTransport & transport = server.getServerTransport();
RCF::AsioServerTransport & asioTransport = dynamic_cast<RCF::AsioServerTransport &>(transport);
boost::asio::io_service & ioService = asioTransport.getIoService();

当RcfServer停止时,io_service将被销毁。

3.21 How do I detect client disconnections, from server-side code?(如何从服务器端代码检测客户机断开连接?)

当client断开连接时,server上的关联RcfSession将被销毁。可以使用RcfSession::setOnDestroyCallback(),在发生这种情况时通知应用程序代码。

void onClientDisconnect(RCF::RcfSession & session){
    // ...
}

class ServerImpl{
    void SomeFunc(){
        // From within a remote call, configure a callback on the current RcfSession.  
        RCF::getCurrentRcfSession().setOnDestroyCallback( boost::bind(
            onClientDisconnect,
            _1));
    }
}

bind()可用于向callback函数传递额外的参数。

3.22 How do I pass a security token from the client to the server, without changing the RCF interface?(如何在不更改RCF接口的情况下将安全令牌从客户机传递到服务器?)

您可以使用用户数据槽(ClientStub::setRequestUserData(), RcfSession::getRequestUserData()),将特定于应用程序的数据从客户机传递到服务器。请参阅每个请求的用户数据

3.23 Can I send std::wstring objects between Linux and Windows?(我可以在Linux和Windows之间发送std::wstring对象吗?)

在RCF 1.2和更早的版本中,存储为std::wstring的Unicode字符串被序列化为wchar_t字符序列。如果客户机和服务器运行在具有不同std::wstring编码的平台上,比如Linux和Windows,这将导致序列化错误。
在RCF 1.3及更高版本中,std::wstring以UTF-8编码进行序列化,根据平台的不同,可以在UTF-16或UTF-32之间进行转换。参见高级序列化 - Unicode字符串。

3.24 Can I send UTF-8 encoded std::string objects between Linux and Windows?(我可以在Linux和Windows之间发送UTF-8编码的std::string对象吗?)

可以 —— SF将std::string序列化为一个8位字符序列,所以编码是ASCII、ISO-8859-1、UTF-8还是其他任何东西都无关紧要。你的应用程序只需要知道它自己字符串的编码。

4. Miscellaneous

4.1 为什么这么多例子中都有双括号?

以下代码片段将导致编译器错误:

int port = 0;
RcfClient<I_Echo> client( RCF::TcpEndpoint(port));
RCF::RcfServer server( RCF::TcpEndpoint(port));

// 将在这两行上得到编译器错误…
client.getClientStub();
server.start();

由于C++语言的特殊性,client和server的声明实际上被解释为函数声明,接收一个名为port的RCF::TcpEndpoint参数。C++编译器以这种方式解释声明,以保持与C的向后兼容性。
为了消除这种歧义,我们需要在RCF::TcpEndpoint周围加上额外的括号:

int port = 0;
RcfClient<I_Echo> client(( RCF::TcpEndpoint(port)));
RCF::RcfServer server(( RCF::TcpEndpoint(port)));

// Now its OK.
client.getClientStub();
server.start();

C++语言的这种怪癖有时被称为“C++最烦人的解析”。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值