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.
On Windows, yes. See Performance.
For local RPC, RCF supports named pipe transports (Win32NamedPipeEndpoint
),
which are backed by shared memory.
Yes - see Transport configuration.
RcfClient<>
instancesd?RcfClient<>
object connect to the server?asio::io_service
used by the RCF server?std::wstring
objects between Linux and Windows?std::string
objects between Linux and Windows?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.
Use servant binding names. See Binding servant objects.
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".