Delta V Software

Appendix - FAQ

RCF User Guide


PrevUpHome

If you have defined RCF_USE_BOOST_SERIALIZATION, RCF will need to link to the Boost.Serialization libraries.

If you have defined RCF_USE_BOOST_FILESYSTEM, RCF will need to link to the Boost.Filesystem and Boost.System libraries.

RCF does not link to any other Boost libraries.

Boost libraries have an auto linking feature that may cause your linker to look for the wrong file to link to. You can define BOOST_ALL_NO_LIB, and then explicitly tell the linker which files to link to.

Yes. To export RCF functions from a DLL you will need to define RCF_BUILD_DLL.

Because of header ordering issues with the Windows platform headers <windows.h> and <winsock2.h>. Including <windows.h> will by default include an older version of Winsock, and makes it impossible to subsequently include <winsock2.h> in the same translation unit.

The easiest workaround for this issue is to define WIN32_LEAN_AND_MEAN, before including <windows.h>.

Yes, if the following warnings are disabled:

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

Probably, but you may need to make minor modifications to RCF yourself, to accomodate platform specific issues, such as which platform headers to include.

On Windows, if you are using TCP transports, you'll need to link to ws2_32.lib. On *nix platforms, you'll need to link to libraries like libnsl or libsocket.

No. RCF 1.3.1 is the last RCF version that supports Visual C++ 6.

If you define external serialization functions in a header file, without the inline modifier, and include them in two or more source files, you will get linker errors about duplicate symbols. The solution is to either add an inline modifier:

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

, or to declare the serialization function in a header and define it in a source file :

// X.hpp
void serialize(SF::Archive & ar, X & x);

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

If you include RCF headers into commonly used application headers of your own, you may notice an increase in build time, as the compiler will parse the RCF headers once for every source file that happens to include them.

You should only include RCF headers when you need to - in other words, only include them into source files that use RCF functionality. In your application header files, you should be able to use forward declarations, rather than including the corresponding header files.

For example, if you are defining a class X with a RcfClient<> member, you can forward declare the RcfClient<>, and then use a pointer for the member:

// 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(...) ) 
{}

You can then include X.h anywhere in your application, without including any RCF headers.

Whenever an outgoing TCP connection is made, a local port number has to be assigned to the connection. On Windows XP, those local ports (sometimes referred to as ephemeral ports) are by default assigned from a range of about 4000 port numbers.

If you create many RcfClient<> objects, with TCP endpoints, you will eventually exhaust the available ports, as Windows holds on to them for a short while after the connection is closed.

You should use as few TCP connections as possible (use the same RcfClient<> object instead of creating new ones). There are also registry settings on Windows XP that alleviate the issue. Locate the following key:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters

, and set

TcpNumConnections = 0x800, MaxUserPort = 65534

After restarting, the system will allow an expanded range of ephemeral ports.

Probably because RCF::deinit() has not yet been executed.

For local RPC, RCF supports named pipe transports (Win32NamedPipeEndpoint), which are backed by shared memory.

Either run remote calls on a non-UI thread, or use progress callbacks to repaint the UI at short intervals. See Progress callbacks.

Use a progress callback (see Progress callbacks). You can configure the callback to be called at any given frequency, and when you want to cancel the call, throw an exception.

You can't call RcfServer::stop() from within a remote call, because the stop() call will wait for all worker threads to exit, including the thread calling stop(), hence causing a deadlock. If you really need to stop the server from within a remote call, you can start a new thread to do so:

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;
}

Make RcfClient<> a friend of your implementation class:

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;
    }
};

You can move network connections from one RcfClient<> to another. See Access to underlying transport.

Yes. As long as a subscriber is able to initiate a connection to the publisher, it will receive published messages.

Pointers can't be used as return types in RCF interfaces, because there is no safe way of marshaling them. Pointers can however be used as in parameters to a remote call, and behave essentially like a reference.

Specify a port number of zero in the RCF::TcpEndpoint object passed to the RcfServer constructor. After the server is started, retrieve the port number by calling RcfServer::getIpServerTransport().getPort().

Call RCF::getCurrentRcfSession().disconnect() in your server implementation.

The publisher won't know, because messages are published using oneway semantics.

In the RCF::TcpEndpoint passed to your RcfServer, you need to specify 0.0.0.0 as the IP address, to allow clients to access it through any network interface. By default 127.0.0.1 is used, which restricts clients to running on the same machine as the server.

When getClientStub().connect() is called, or a remote call is made.

Probably because your program has a global static object whose destructor is trying to destroy a RcfClient<> or RcfServer object (or some other RCF object), after RCF has been deinitialized.

Make sure you destroy all RCF objects before deinitializing RCF.

Call RCF::getCurrentRcfSession().getClientAddress() in your server implementation.

SF will serialize and deserialize enums automatically, as integer representations.

You can use disconnect notifications, or poll the subscriber for connectedness. See Publish/subscribe.

You can call 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();

The io_service will be destroyed when the RcfServer is stopped.

When a client disconnects, the associated RcfSession on the server is destroyed. You can use RcfSession::setOnDestroyCallback(), to notify your application code when this happens.

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));
    }
}

boost::bind() can be used to pass extra arguments to the callback function.

You can use user data slots (ClientStub::setRequestUserData(), RcfSession::getRequestUserData()) , to pass application specific data from the client to the server. See Per-request user data.

In RCF 1.2 and earlier, Unicode strings stored as std::wstring, were serialized as a sequence of wchar_t characters. This would cause serialization errors if the client and server were running on platforms with different std::wstring encodings, such as Linux and Windows.

In RCF 1.3 and later, std::wstring is serialized in UTF-8 encoding, with conversions to and from UTF-16 or UTF-32, depending on the platform. See Advanced Serialization - Unicode strings.

Yes - SF serializes std::string a sequence of 8-bit characters, so it doesn't matter whether the encoding is ASCII, ISO-8859-1, UTF-8, or anything else. Your application just needs to be aware of the encoding of its own strings,

The following code snippet will cause compiler errors:

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

// Will get compiler errors on both of these lines...
client.getClientStub();
server.start();

Because of a C++ language idiosyncracy, the declarations of client and server are actually interpreted as function declarations, taking a RCF::TcpEndpoint parameter named port. C++ compilers interpret the declarations this way to maintain backwards compatibility with C.

To clear up this ambiguity, we need to put in extra parentheses around the 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();

This quirk of the C++ language is sometimes referred to as "C++'s most vexing parse".


PrevUpHome