PrevUpHomeNext

Remote Calls - Server-side

Configuring a server
Server-side sessions

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:

  • The transport being used:

RCF::RcfSession & session = RCF::getCurrentRcfSession();
RCF::TransportType transportType = session.getTransportType();

  • The network address of the client:

const RCF::RemoteAddress & clientAddress = session.getClientAddress();
std::string strClientAddress = clientAddress.string();

  • The current request header:

RCF::RemoteCallRequest request = session.getRemoteCallRequest();

  • Any custom request data passed in by the client:

std::string customRequestData = session.getRequestUserData();

  • You can create, retrieve and delete session objects:

session.createSessionObject<MySessionObj>();
MySessionObj & obj = session.getSessionObject<MySessionObj>();
MySessionObj * pObj = session.querySessionObject<MySessionObj>();
session.deleteSessionObject<MySessionObj>();

  • How long the client has been connected:

// 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();

  • How many calls have been made on this connection:

boost::uint32_t callsMade = session.getRemoteCallCount();

  • How many bytes have been sent and received on this connection:

boost::uint64_t totalBytesReceived = session.getTotalBytesReceived();
boost::uint64_t totalBytesSent = session.getTotalBytesSent();


PrevUpHomeNext