On the server-side,
RCF::RcfServer is the fundamental class responsible for dispatching remote calls from clients. A
RcfServer contains one or more transports, on which it listens for remote calls from clients. A
RcfServer also exposes one or more servant bindings, to which it dispatches remote calls that come in from clients.
A minimal example of a server was shown in the Tutorial. First, a
RcfServer is created with a TCP transport:
Then a servant binding is configured for the
Finally, the server is started and begins to respond to remote calls from clients:
RcfServer listens on one or more transports, for remote calls from clients. If you are setting up a server with only a single transport, you can supply the corresponding
RCF::Endpoint parameter to the
Alternatively, to configure multiple transports, you can use
To perform additional transport-related configuration, you can capture the return value from
Servant objects are responsible for the actual server functionality of your application. When a
RcfServer receives a remote call request from a client, it uses the servant binding name specified in the request to locate the relevant servant binding, and then dispatches the remote call to the relevant function on that servant object.
Servant objects are always bound to a RCF interface. To create a servant binding, use
RCF::RcfServer::bind<>(). Each binding on the server is identified by its binding name, which is normally the runtime name of the RCF interface used in the binding.
So the following code:
, creates a servant binding with the servant binding name
The servant binding name can also be set explicitly:
Every remote call request from a client includes a servant binding name, which is used by the server to dispatch the remote call. The default servant binding name supplied by a RCF client is the runtime name of the RCF interface it is using. So the following client code:
, makes a remote call which is dispatched by the server to a servant object with the servant binding name
The client can also set the servant binding name explicitly:
, to dispatch the call to the nominated servant binding.
RcfServer instance will not start dispatching remote calls until
RCF::RcfServer::start() is called.
The server can be stopped manually by calling
The server will be stopped automatically if the
RcfServer object goes out of scope.
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
RCF::ThreadPool can be configured to use a fixed number of threads, or a varying number of threads depending on server load:
A thread pool assigned to the
RcfServer will be shared by all the transports of that
You can also use
RCF::ServerTransport::setThreadPool() to assign thread pools to specific transports:
RCF creates a server-side
RCF::RcfSession object for each connection to the server. The
RcfSession object has a lifetime that matches that of the client connection, and provides a mechanism for server-side code to persist state across remote calls on the same client connection.
From within a servant object executing a remote call, you can access the
RcfSession by calling
Session objects are application C++ objects that are stored in the RCF session, and thus persisted across remote calls on the same connection. A typical use case for session objects is to associate application specific information with a connection. For example, application logic may require that after a client connects, the first thing it should do is call a
Login() method. If the
Login() method succeeds, the authenticated state of the connections needs to be persisted so that subsequent calls on the same connection can access it.
The following functions provide access to session objects:
Session objects can be of arbitrary type, and their lifetime is controlled by the lifetime of the client connection. When the client connection is closed, any session objects associated with it are destroyed.
For an example of using session objects to store authentication state, see Access Control.
As described in Client-side Programming, a remote call can have extra user data associated with it, apart from the parameters of the remote call. Both the remote call request and the remote call response can carry such data, and you can use the following
RcfSession functions to access that data:
You can use
RcfSession to find out a number of things about the current client connection, including:
For more information, see the reference documentation for
RCF allows you to apply access controls to individual servant bindings on your server. The access control is implemented as a user-defined callback function, in which you can apply application-specific logic to determine whether a client connection should be allowed to access a particular servant binding.
The access control callback will be invoked by the
RcfServer each time a client tries to call a method on that servant binding.
From the access control callback you can inspect the current session and determine whether it should be granted access to the servant. Once authentication is granted, you will probably want to store the authentication state in a session object, so it can be easily reused on subsequent calls:
This example uses the access control callback to inspect the transport protocol the client is using, and uses that to determine the identity of the client.
In some situations you may want the client to provide extra authentication information, beyond what is available though the transport protocol. This typically means having the equivalent of a
Login() method on the interface, that needs to be called before any other method on the interface. The access control callback can be used to verify that
Login() is called before any other method:
In this case, the access control callback allows calls to
Login() to go through, while for any other method on the
I_PrintService interface, it checks for the existence of the authentication state that the
Login() call creates.
Login() method is identified in the access control callback by its method ID - in this case 0, as it is the first method on the interface. Method ID's are assigned in incremental order, from 0, so if for example
Login() had been the third method on the interface, it would have had a method ID of 2.
Server objects are application specific objects that are created by your server-side code and stored in the
RcfServer. Unlike session objects (which are stored in
RcfSession), server objects persist and are accessible outside of the RCF session in which they were created. The lifetime of server objects is managed by
RCF::RcfServer, using a garbage collection policy.
Server objects are manipulated with the following functions:
Here is how we would create and update a server-wide session object for authenticated users:
This code creates a
PrintServiceSession object for each authenticated user. The
PrintServiceSession object will be shared across all connections associated with that authenticated user.