On the server-side, your application is responsible for dispatching remote
calls from clients. Typically you will create a RcfServer
:
RCF::RcfServer server( RCF::TcpEndpoint(50001) );
, bind a servant object to it:
HelloWorldImpl helloWorldImpl; server.bind<I_HelloWorld>(helloWorldImpl);
, and start the server:
server.start();
When a client makes a remote call to the I_HelloWorld
interface, the relevant member function of the servant object is executed.
From within the servant object, you can access the current server side remote
call session through RCF::getCurrentSession()
:
class HelloWorldImpl { public: void Print(const std::string & s) { std::cout << "I_HelloWorld service: " << s << std::endl; RCF::RcfSession & session = RCF::getCurrentRcfSession(); // ... } };
RCF::getCurrentSession()
returns a RcfSession
reference,
through which server-side per-session configuration is done. A RcfSession
is created for every connection
to a RcfServer, and it's lifetime matches that of the underlying transport
connection.
A RcfServer
listens on
one or more transports, for remote calls from clients. Server transports
can be configured by passing in an endpoint parameter to the RcfServer
constructor:
RCF::RcfServer server( RCF::TcpEndpoint(50001) );
Alternatively, to configure multiple transports, use RcfServer::addEndpoint()
:
RCF::RcfServer server; server.addEndpoint( RCF::TcpEndpoint(50001) ); server.addEndpoint( RCF::UdpEndpoint(50002) );
A RcfServer
instance will
not start dispatching remote calls until RcfServer::start()
is called. The server can be stopped
manually by calling RcfServer::stop()
:
RCF::RcfServer server( RCF::TcpEndpoint(50001) ); server.start(); // ... server.stop();
You can also simply let the RcfServer
object go out of scope, in which case the server is stopped automatically.
RcfServer::bind<>()
is used to bind servant objects to RCF interfaces. Every bound servant
object has a binding name which identifies it. The default servant binding
name is the runtime name of the interface it is exposed through. So the
following code:
server.bind<I_HelloWorld>(helloWorldImpl);
, creates a servant binding with the servant binding name "I_HelloWorld"
, as that is the
runtime identifier of the I_HelloWorld
interface:
RCF_BEGIN(I_HelloWorld, "I_HelloWorld") RCF_METHOD_V1(void, Print, const std::string &) RCF_END(I_HelloWorld)
The servant binding name can also be set explicitly:
server.bind<I_HelloWorld>(helloWorldImpl, "CustomBindingName");
Each remote call from a client specifies a servant binding name, which
is used by the server to dispatch the remote call. The servant binding
name supplied by a RcfClient<>
defaults to the runtime name of
the RCF interface it is using. So the following client code:
RcfClient<I_HelloWorld> client( RCF::TcpEndpoint(50001) ); client.Print("Hello World");
, will make a remote call to the servant object with the servant binding
name "I_HelloWorld"
.
The client can also set the servant binding name explicitly:
RcfClient<I_HelloWorld> client( RCF::TcpEndpoint(50001), "CustomBindingName" ); client.Print("Hello World");
, to get the call dispatched to the nominated servant binding.
By default, a RcfServer
will use a single thread to dispatch calls across all its transports. This
behavior can be modified by explicitly assigning a thread pool to the
RcfServer
:
RCF::RcfServer server( RCF::TcpEndpoint(50001) ); RCF::ThreadPoolPtr threadPoolPtr( new RCF::ThreadPool(1, 5) ); server.setThreadPool(threadPoolPtr);
RCF::ThreadPool
can be configured to use a
fixed number of threads, or a varying number of threads depending on server
load:
// Thread pool with a fixed number of threads (5). RCF::ThreadPoolPtr threadPoolPtr( new RCF::ThreadPool(5) ); server.setThreadPool(threadPoolPtr);
// Thread pool with a dynamically varying number of threads (1-25). RCF::ThreadPoolPtr threadPoolPtr( new RCF::ThreadPool(1, 25) ); server.setThreadPool(threadPoolPtr);
A thread pool assigned to the RcfServer
will be shared by all the transports of that RcfServer
.
It is also possible to assign thread pools to specific transports:
RCF::RcfServer server; RCF::ThreadPoolPtr threadPool1( new RCF::ThreadPool(1) ); server.addEndpoint( RCF::TcpEndpoint(50001) ).setThreadPool(threadPool1); RCF::ThreadPoolPtr threadPool2( new RCF::ThreadPool(1) ); server.addEndpoint( RCF::TcpEndpoint(50002) ).setThreadPool(threadPool2);
You can use RcfSession
to
find out a number of things about the current client connection, including:
RCF::RcfSession & session = RCF::getCurrentRcfSession(); RCF::TransportType transportType = session.getTransportType();
const RCF::RemoteAddress & clientAddress = session.getClientAddress(); std::string strClientAddress = clientAddress.string();
RCF::RemoteCallRequest request = session.getRemoteCallRequest();
std::string customRequestData = session.getRequestUserData();
session.createSessionObject<MySessionObj>(); MySessionObj & obj = session.getSessionObject<MySessionObj>(); MySessionObj * pObj = session.querySessionObject<MySessionObj>(); session.deleteSessionObject<MySessionObj>();
// When the connection was established, as reported by CRT time() function. time_t connectedAt = session.getConnectedAtTime(); // Connection duration in seconds. boost::uint32_t connectionDurationS = session.getConnectionDuration();
boost::uint32_t callsMade = session.getRemoteCallCount();
boost::uint64_t totalBytesReceived = session.getTotalBytesReceived(); boost::uint64_t totalBytesSent = session.getTotalBytesSent();