Introduction to how clients interact with servers through a client side API encapsulated in a session. A complex server may also provide subsession classes.
A server usually runs in a separate process to the client. The server provides a client side API that enables clients to create sessions and send requests to the server. This client side API is packaged as a DLL against which the client code links. For example, to create a Socket Server session the client links against esock.lib and to create a File Server session the client links against efsrv.lib.
All
communication with the server is session based. This means that the
client must create a session with the server before making any requests.
Creating a session involves instantiating the class that encapsulates
the client side API and then calling a function to create a session.
This function is usually called Open()
or Connect()
. The client side API is a Symbian R class derived
from RSessionBase
. This class encapsulates the details
of session creation and sending requests to the server.
Link against the library file (.lib) that contains the client side API.
Instantiate
the class that encapsulates the client side API. This always derives
from RSessionBase
.
Call the function that creates a session.
Call functions from the client side API that make requests of the server.
Close the session.
What is a session?
On the server side there is a server object, derived from CServer2
. This is an active object. It is responsible for
creating server side sessions and for routing client requests to the
correct server side session.
Each client that connects with the server is represented on
the server side by an instance of an object derived from CSession2
.
Each client has an RSessionBase
derived object.
This object is a handle and is derived from RHandleBase
. The two session objects communicate via the kernel.
Figure: Main classes of the client server framework
Using subsessions
Some servers, especially system servers with
rich functionality, provide more than one class as their client side
API. In this case using the server typically involves creating both
session and subsession objects. For example, to represent a file in
the file system it is necessary first to create an RFs
object, which is a File Server session, and then an RFile
object. The RFile
is called a subsession because
it makes use of an existing session. This allows you to create several
files without incurring the overhead of creating multiple sessions.
You must always create a session before you can use a subsession. The subsession uses the session to communicate with the server. When you open a subsession you pass the session as a parameter in order to associate the session and subsession. Here is an example, with error handling omitted for clarity.
// Create a File Server session object. RFs fs; // Connect to the File Server. // This calls RSessionBase::CreateSession(). fs.Connect(); // Create the subsession that represents an individual file. RFile file; // The name of the file to be opened. _LIT( KDataFileName, “C:\\data\\temp.txt” ); // Open the subsession, passing the session object as the first parameter. file.Open( fs,KDataFileName ); // Manipulate the file using RFile methods. ... // Close both the subsession and the session to ensure clean up // of server resources. file.Close(); fs.Close();
The server functionality consists in multiple logical API groupings, for example file operations and directory operations.
To represent multiple objects efficiently, for example multiple files or sockets.
To represent objects that are created and destroyed regularly, for example windows.
It is up to the server author to provide clients with a meaningful
and convenient client side API. In cases where client requests may
take a long or unpredictable period to complete, the server should
offer asynchronous functions as part of the client side API. For example,
the RFile
class offers both synchronous and asynchronous
overloads of Read()
and Write()
,
as shown below:
class RFile : public RSubSessionBase { public: IMPORT_C TInt Open( RFs& aFs, const TDesC& aName, TUint aFileMode ); IMPORT_C TInt Read( TDes8& aDes ) const; IMPORT_C void Read( TDes8& aDes, TRequestStatus& aStatus ) const; IMPORT_C TInt Write( const TDesC8& aDes ); IMPORT_C void Write( const TDesC8& aDes, TRequestStatus& aStatus ); ... };
Asynchronous functions in Symbian always take a TRequestStatus
argument. For more on managing asynchronous
functions, see Introduction to active objects.