RSessionBase::Send sends a message to the serverbut does not receive a reply and in practice, this function is rarely used.The Send and SendReceive methods take a 32-bit argu-ment aFunct
Trang 1The methods of this class are used to send messages to the server You’llnotice that most of them are protected This is because the client-side classwhich accesses a server will typically derive from RSessionBase (forexample, class RFs, which provides access to the file server) The derivedclass exports functions that wrap RSessionBase communication withthe server and are more meaningful to potential clients of the server (such
as RFs::Delete() or RFs::GetDir())
The overloads of RSessionBase::CreateSession() start a newclient–server session They are typically called by client-side implemen-tation code in an exported method such as Open() or Connect()
As an example, when you start a session with the file server youcall RFs::Connect(), which itself calls RSessionBase::Create-Session() When the session is opened successfully, correspondingkernel and server-side objects are created
A server has a unique name which must be passed to Base::CreateSession()to connect the client to the correct server.Again, the client-side implementation takes care of this, so the callingclient does not need to know the name of the server CreateSession()also takes a TVersion structure4for compatibility support
RSession-You’ll notice that one overload of CreateSession() takes an ger parameter called aAsyncMessageSlots This value reserves anumber of slots to hold any outstanding asynchronous requests thatclient session may have with the server.5The maximum number of slotsthat may be reserved for each server is 255 The other overload ofCreateSession()does not pre-allocate a maximum number of mes-sage slots Instead, they are taken from a kernel-managed pool, of up
inte-to 255 message slots for that server, which is available inte-to the wholesystem If the number of outstanding requests to a server exceeds thenumber of slots in the system pool, or the number reserved for a particu-lar session, the asynchronous request fails to be submitted and completesimmediately with the error KErrServerBusy
A request to a server is issued through a call to Base::SendReceive() or RSessionBase::Send() Send-Receive()has overloads to handle both synchronous and asynchronousrequests The asynchronous request method takes a TRequestStatus¶meter, while the synchronous version returns the result in the TIntreturn value RSessionBase::Send() sends a message to the serverbut does not receive a reply (and in practice, this function is rarely used).The Send() and SendReceive() methods take a 32-bit argu-ment (aFunction) that identifies the client request (typically defined
RSession-in an enumeration shared between the client and server – see theTHerculeanLabors enumeration in the sample code of Chapter 12
4 A TVersion object contains three integers representing the major, minor and build version numbers.
5 A session can only ever have one outstanding synchronous request with a server.
Trang 2WHAT CLASSES DOES THE CLIENT–SERVER FRAMEWORK USE? 173
for an example) The methods also take a TAny* argument which is
a pointer to an array of four 32-bit values This array constitutes the
”payload” for the request; it can be empty or it may contain up to fourinteger values or pointers to descriptors in the client’s address space Thelayout of the array is determined in advance for each request betweenclient and server and is a private protocol The calling client does notneed to have any knowledge of how data is transferred
If a server supports session sharing, a client session may be shared by allthe threads in a client process (Symbian OS v8.0 is the first release whichalso allows a session to be shared between processes) However, someservers restrict the session to the thread which connected to the serveralone (this was always the case until sharable sessions were introduced
in Symbian OS v6.0) I’ll discuss sharable sessions in more detail later inthis chapter
On the client side, if a session can be shared, the first connection tothe server should be made as normal using RSessionBase::Create-Session() Once the session is opened, RSessionBase::Share()should be called on it to make it sharable.6Until Share() is called, thesession is specific to the connecting client thread If the TAttachModeparameter passed to Share() is EExplicitAttach, other threadswishing to share the session should call RSessionBase::Attach()
on the session However, if EAutoAttach is passed to Share(), thenall threads are attached to the session automatically If the session is notattached before a message is sent, or the session is not sharable, a panicoccurs (KERN-SVR 0)
Client requests are identified using an enumeration shared between the client and server Requests are submitted with a payload array which can contain up to four 32-bit values (integer values or pointers to descriptors in the client’s address space).
RMessage
An RMessage object is a server-side representation of a client request,and each client request to the server is represented by a separateRMessageobject Here is the definition from e32std.h, where again,I’ve shown only the most relevant methods:
class RMessage {
Trang 3IMPORT_C void Complete(TInt aReason) const;
IMPORT_C void ReadL(const TAny* aPtr,TDes8& aDes) const;
IMPORT_C void ReadL(const TAny* aPtr,TDes8& aDes, TInt anOffset) const;
IMPORT_C void ReadL(const TAny* aPtr,TDes16& aDes) const;
IMPORT_C void ReadL(const TAny* aPtr,TDes16& aDes, TInt anOffset) const;
IMPORT_C void WriteL(const TAny* aPtr,const TDesC8& aDes) const;
IMPORT_C void WriteL(const TAny* aPtr,const TDesC8& aDes, TInt anOffset) const;
IMPORT_C void WriteL(const TAny* aPtr,const TDesC16& aDes) const;
IMPORT_C void WriteL(const TAny* aPtr,const TDesC16& aDes, TInt anOffset) const;
IMPORT_C void Panic(const TDesC& aCategory,TInt aReason) const;
IMPORT_C void Kill(TInt aReason) const;
IMPORT_C void Terminate(TInt aReason) const;
inline TInt Function() const;
inline const RThread& Client() const;
inline TInt Int0() const;
inline TInt Int1() const;
inline TInt Int2() const;
inline TInt Int3() const;
inline const TAny* Ptr0() const;
inline const TAny* Ptr1() const;
inline const TAny* Ptr2() const;
inline const TAny* Ptr3() const;
inline const RMessagePtr MessagePtr() const;
The RMessage object stores the 32-bit request identifier (also known
as an ”opcode”), which can be retrieved by calling Function() Italso holds the array of request payload data, a handle to the clientthread, accessible through Client(), and the client’s RHandleBaseidentification handle
As I described above, the layout of the request parameters in therequest data array is pre-determined for each client request For requestswhere the server expects parameters from the client, it can retrieve thedata from an RMessage object using Int0() to return a 32-bit valuefrom the first element of the request array, Int1() to return the secondelement, and so on In a similar manner, Ptr0() returns the contents ofthe first element in the request array as a TAny* pointer, Ptr1() for thesecond element, and so on to the fourth element of the array
The pointers returned from Ptr0() to Ptr3() cannot be useddirectly by the server code if they refer to the address space of aclient running in a different process The server must instead pass
Trang 4WHAT CLASSES DOES THE CLIENT–SERVER FRAMEWORK USE? 175
these pointers to the overloaded ReadL() and WriteL() methods7
of RMessage, which use kernel-mediated inter-process communication
to transfer the data
When the server has serviced a client request, it calls Complete()
on the RMessage to notify the client This method wraps a call toRThread::Complete() on the client’s thread handle The integervalue passed to Complete() is written into the client’s TRequest-Statusvalue and the request semaphore for the client thread is signaled
If you’re wondering about synchronous SendReceive() requests fromthe client, which don’t take a TRequestStatus parameter, take a look
at Section 11.5 The Panic(), Terminate() and Kill() methods
of RMessage are wrappers over the RThread methods of the samename and may be used by the server to stop the client thread undercertain circumstances, such as client misbehavior due to a program-ming error
The client and server run in separate threads which also typically run in different processes The address spaces of Symbian OS processes are protected and kernel-mediated data transfer must be used between the client and server.
CSharableSession
CSharableSessionis an abstract base class that represents a sessionwithin the server For each RSessionBase-derived object on the clientside, there is an associated CSharableSession-derived object on theserver side
7 These methods are simply wrappers over the ReadL() and WriteL() methods of RThread , as described in Chapter 10.
Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com
Trang 5KERNEL SIDE USER SIDE
CLIENT PROCESS
SERVER PROCESS
DThread (Client)
DSession RSessionBase
doubly linked list of CSharableSession objects
DServer holds a doubly linked list of DSession objects
CSession
Figure 11.2 Symbian OS client- and server-side base classes
class CSharableSession : public CBase {
friend class CServer;
public:
IMPORT_C ∼CSharableSession()=0;
IMPORT_C virtual void CreateL(const CServer& aServer);
inline const CServer* Server() const;
inline const RMessage& Message() const;
IMPORT_C void ResourceCountMarkStart();
IMPORT_C void ResourceCountMarkEnd();
IMPORT_C virtual TInt CountResources();
virtual void ServiceL(const RMessage& aMessage)=0;
Trang 6WHAT CLASSES DOES THE CLIENT–SERVER FRAMEWORK USE? 177
CSharableSession provides methods to access the derived object, Server(), which I’ll discuss shortly Message() can
CServer-be used to access the next client request to process, if there anyare outstanding If the server makes an asynchronous call to servicethe request and does not complete the request before returning fromServiceL(), the RMessage object must be stored so it can be com-pleted at a later stage If it was not stored, when it came to complete therequest, Message() would return a different message if other requestshad been submitted to the server while the asynchronous request wasbeing processed
Classes derived from CSharableSession handle incoming clientrequests through their implementation of the pure virtual ServiceL()method Typically, this method should check the incoming message tosee which request the client has submitted, then handle it by unpackingthe message and using the incoming parameters accordingly When therequest has been handled, the server calls RMessage::Complete()
to notify the client thread of request completion The example code inChapter 12 illustrates this
You’ll notice a set of resource-counting functions, CountMarkStart(), ResourceCountMarkEnd() and Count-Resources(), which have a default, ”do nothing” implementation in theCSharableSessionbase class but which may be overridden by derivedclasses for customized resource checking at server startup and shutdown,usually used only in debug builds ResourceCountMarkStart() ini-tializes server resource counting while ResourceCountMarkEnd()checks that the current number of server resources (e.g subsessions) inuse is equivalent to that when resource counting started If the valuesare not equal, the function panics the client thread associated with themost recent message CountResources() returns the number of serverresources currently in use
Resource-Prior to Symbian OS v6.0, class CSession represented a session onthe server side The CSession class was thread-specific and accessibleonly by a single thread on the client side Symbian OS v6.0 introducedthe concept of sharable client–server sessions From v6.0, a client sessionmay potentially be shared between multiple threads in the same clientprocess, although a server implementation is not required to supportsharable sessions To support this modification, Symbian OS v6.0 intro-duced CSharableSession as the base class for a server-side session.CSessionstill exists, deriving from CSharableSession, as an abstractclass which provides a set of thread-specific functions to transfer databetween client and server
Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com
Trang 7The fundamental server-side base class is CServer, which itself derivesfrom CActive Here’s the definition of CServer from e32base.h,with the less relevant details omitted for clarity:
class CServer : public CActive {
public:
IMPORT_C ∼CServer()=0;
IMPORT_C TInt Start(const TDesC& aName);
IMPORT_C void StartL(const TDesC& aName);
IMPORT_C void ReStart();
inline const RMessage& Message() const;
protected:
IMPORT_C CServer(TInt aPriority, TServerType aType=EUnsharableSessions);
IMPORT_C void DoCancel();
IMPORT_C void RunL();
If the request is to connect a new session, CServer::RunL() callsthe NewSessionL() method of the derived class, which creates a newserver-side session object If it is a request from a client-side session
to disconnect, the associated server-side session object is destroyed
in CServer::RunL() For other client requests, CServer::RunL()calls the ServiceL() method of the associated CSharableSession-derived object to service the request Having serviced each request,CServer::RunL()resubmits a ”message receive” request and awaitsfurther client requests
When you are implementing a server, you must create an active uler as part of server startup (as I described in Chapter 8, which covers
Trang 8sched-HOW IS A SERVER STARTED? 179
the basics of active objects) I’ll illustrate how to do this in the examplecode for a typical server in the next chapter CServer::StartL()adds the server to the active scheduler and initiates the first messagereceive request
For each CServer object created in the system, a correspondingDServer object is created in the kernel Each DServer object holds
a doubly-linked queue of all DSessions, representing all the currentlyopen sessions for that server It also owns a kernel object, DThread,which represents the server thread
When implementing a server, you must create an active scheduler during server startup.
11.5 How Do Synchronous and Asynchronous
Requests Differ?
A client can request synchronous or asynchronous services8from a server.Asynchronous requests take a TRequestStatus reference parameter,which is passed to RSessionBase::SendReceive() This parameter
is filled with a completion result by the server, via the kernel, when therequest is completed by a call to RThread::RequestComplete(),which also signals the request semaphore of the client thread to notify it
of request completion
In fact, synchronous requests to the server are actually synchronous” The synchronous overload of RSessionBase::Send-Receive() declares a TRequestStatus object locally, passes this
”pseudo-to the asynchronous overload of SendReceive() and then blocks theclient thread until the request completes In effect, the client thread issuspended and notified only when a server has completed its action,rather than continuing to poll the server for the status of a request This isimportant on Symbian OS, to minimize power consumption
11.6 How Is a Server Started?
There are several ways in which a server can be started and stopped:
• System servers, e.g the file server, are started by Symbian OS as part
of OS startup because they are essential to the operating system
8 For each asynchronous request function a server API provides, it must also provide a cancellation method.
Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com
Trang 9• Application servers, which are only needed when certain applicationsare running, are started when clients need to connect to them If
an application attempts to start a server that is already running, saybecause it has been started by another application, no error resultsand only a single instance of the server runs When the server has
no outstanding clients, that is, when the last client session closes,
it should terminate to save system resources This type of server isknown as a transient server I’ll illustrate startup and shutdown for thiskind of server in the next chapter
• Other servers, e.g the POSIX server, are required by only a singleapplication and are started with that application and closed when
it terminates
11.7 How Many Connections Can a Client Have?
A client can have multiple ”connections” to a server through one or moresessions as follows:
• Each connection can use a separate client–server session opened by
a call to RSessionBase::CreateSession() The sessions areindependent of any other within the client thread, and each maintainsits own context That is, each client session has a correspondingCSharableSessionobject in the server and DSession object inthe kernel Use of multiple client sessions where they are not strictlynecessary should be limited to reduce the number of kernel and serverresources consumed – I’ll discuss this further later in this chapter
• The client may create a number of subsessions within a single session
(the use of subsessions is described in Section 11.14) Client–servercommunication occurs via the owning session, using a unique handle
to identify each individual subsession The use of separate subsessions
is more lightweight than separate sessions because it uses fewerkernel resources However, they are more complex to implementserver-side
• The server may support sharable sessions Up to 255 threads in aclient process may share a single session
11.8 What Happens When a Client Disconnects?
Typically, a class used to access a server has a termination method,which is usually called Close() Internally, this method will callRHandleBase::Close(), which sends a disconnection message tothe server and sets the session handle to zero On receipt of this message,
Trang 10HOW DOES CLIENT–SERVER COMMUNICATION USE THREADS? 181
the server ends its session with the client by destroying the associatedCSharableSession-derived object (in addition, the kernel will destroythe DSession object which represents the session) If the client has anyoutstanding requests when Close() is called, they are not guaranteed
to be completed
11.9 What Happens If a Client Dies?
For a non-sharable session, if the client dies without calling Close(),the kernel sends a disconnection message to the server to allow it tocleanup sessions associated with that client thread The kernel performsits thread-death cleanup by walking the queue of DSession objects anddestroying any associated with the dead client thread
If the session is sharable, the death of a single client thread does notclose the session – the session is effectively process-relative by virtue ofbeing sharable To destroy the session, either the client process mustterminate or the session must be closed explicitly on the client-side by acall to Close() on an RSessionBase handle
11.10 What Happens If a Server Dies?
If a server dies, the kernel will complete any waiting client requestswith the error code KErrServerTerminated This gives the client
an opportunity to handle request failure and cleanup, destroying anyRSessionBaseobjects open on the server Even if the server is restarted,previous client sessions cannot be reused without first being reconnected
to it, so the only valid operation is to call Close()
11.11 How Does Client–Server Communication
Use Threads?
A session between a client and a server is between one or more clientthreads and a separate server thread Client code runs in user-modethreads It submits requests to server code which also runs in user mode.The channel of communication between client and server is mediated bythe kernel
The Symbian OS server model is thread-based, allowing a server torun either in a separate process to the client, for greater isolation betweenclient and server, or in the same process, to avoid the overhead ofinter-process client–server communication
Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com
Trang 1111.12 What Are the Implications of Server-Side
Active Objects?
The responsiveness of a server can be defined as the maximum timerequired to process a client message or the maximum time required torespond to an event on some device that it controls The server usesnon-pre-emptive active-object event-handling (described in Chapters 8and 9) The response time is determined by the longest possible RunL()event-handler method of any active object running on the server thread,because an active object cannot be pre-empted when it is handling
an event
If a client makes a request while the server thread is already handling
an event in a RunL() method, it runs to completion before the clientrequest can be serviced This is also true for external events occurringfrom resources owned by the server Thus, if you want to write a high-performance server, there should be no long-running RunL() methods
in any active objects in the server’s main thread
This includes processing in the ServiceL() method of theCSharableSession-derived class, which is called byCServer::RunL() This means that long-running operations must beperformed by a separate thread or server
Furthermore, the priority of a server thread should be chosen according
to the maximum guaranteed response time, that is, the longest RunL()method of the server You should not give a high priority to a serverthread that performs lots of processing in its event handler, since it mayblock threads with more appropriately chosen, lower, priorities
11.13 What Are the Advantages of a Local (Same-Process)
Server?
Local servers are useful when several related servers can run in thesame process For example, Symbian OS v7.0 runs the serial communi-cations server, sockets server and telephony server in the same process(C32.exe) The servers are in a different process to their clients, so acontext switch is still required, and resource integrity is maintained bythe separation However, interactions between the three servers occur inthe same process and have a correspondingly lower overhead than theywould otherwise (I’ll describe the overheads associated with using theclient–server model in more detail shortly)
A private local server runs in the same process as its clients It can
be useful, for example, if you need to share client sessions to a serverwhich does not support sharable sessions The client process should use aprivate local server which does support sharable sessions and has a singleopen session with the non-sharable server This private server services
Trang 12WHAT ARE THE OVERHEADS OF CLIENT–SERVER COMMUNICATION? 183
requests from each of the client threads, passing them through as requests
to its single session with the non-sharable server
11.14 What Are the Overheads of Client–Server
Communication?
Session Overhead
Although a client can have multiple sessions with a server, each sessionconsumes limited resources in both the server and the kernel For eachopen client session, the kernel creates and stores a DSession objectand the server creates an object of a CSharableSession-derived class.This means that each connecting session may give rise to a significantspeed overhead Rather than creating and opening multiple sessions ondemand, client code should aim to minimize the number of sessions used.This may involve sharing a session, or, for servers which do not supportthis, passing the open session between functions or defining classes thatstore and reuse a single open session
For efficiency, where multiple sessions are required, a client–serverimplementation may provide a subsession class to reduce the expense ofmultiple open sessions To use a subsession, a client must open a sessionwith the server as normal, and this can then be used to create subsessionswhich consume fewer resources and can be created more quickly This
is done using the RSubSessionBase class, the definition of which isshown below (from e32std.h):
class RSubSessionBase {
public:
inline TInt SubSessionHandle();
protected:
inline RSubSessionBase();
inline RSessionBase& Session();
IMPORT_C TInt CreateSubSession(RSessionBase& aSession, TInt aFunction,const TAny* aPtr);
IMPORT_C void CloseSubSession(TInt aFunction);
IMPORT_C TInt Send(TInt aFunction,const TAny* aPtr) const;
IMPORT_C void SendReceive(TInt aFunction,const TAny* aPtr, TRequestStatus& aStatus) const;
IMPORT_C TInt SendReceive(TInt aFunction,const TAny* aPtr) const; private:
RSub-Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com
Trang 13derived class should provide an appropriate wrapper function (e.g.Open()) which calls RSubSessionBase::CreateSubSession(),passing in an existing RSessionBase-derived session object Create-SubSession() also takes an integer ”opcode” to identify the ”createsubsession” request, and a pointer to an array of pointers (which may beused to pass any parameters required to service the request across theclient–server boundary).
Once the subsession has been created, Receive()and Send() methods can be called, by analogy with those
RSubSessionBase::Send-in RSessionBase, but only three parameters of the request data arraymay be used because the subsession class uses the last element of thedata array to identify the subsession to the server
On the server side, the code to manage client–server subsessionscan be quite complex It usually requires reference counting to man-age subsessions over the lifetime of the session, and typically uses theCObject-derived classes You can find more information about these,somewhat confusing, classes in your SDK documentation
A good example of the use of subsessions is RFile, which derivesfrom RSubSessionBase and is a subsession of an RFs client session
to the file server An RFile object represents a subsession for access
to individual files I’ll illustrate the use of RFs and RFile later in thischapter, but you should consult your SDK for further information aboutthe use of the Symbian OS filesystem APIs
It’s worth noting that connections to the file server can take a significantamount of time to set up (up to 75 ms) Rather than creating multiplesessions on demand, RFs sessions should be passed between functionswhere possible, or stored and reused
Each client–server session has an associated overhead in the kernel and server Client code should minimize the number of sessions
it uses, for example by sharing a session, or by defining classes that store and reuse a single open session A server may also implement subsessions to be used as lightweight alternatives to multiple open sessions.
Performance Overhead
You should be aware of the system performance implications when usingthe client–server model The amount of data transferred between theclient and server does not cause so much of an overhead as thefrequencywith which the communication occurs
The main overhead arises because a thread context switch is necessary
to pass a message from the client thread to the server thread and back
Trang 14WHAT ARE THE OVERHEADS OF CLIENT–SERVER COMMUNICATION? 185
again If, in addition, the client and server threads are running in differentprocesses, a process context switch is also involved
A context switch between threads stores the state of the running thread,overwriting it with the previous state of the replacing thread If the clientand server threads are in the same process, the thread context switchstores the processor registers for the threads If the client and server arerunning in two separate processes, in addition to the thread context,the process context (the address space accessible to the thread), must
be stored and restored The MMU must remap the memory chunks foreach process, and on some hardware this means that the cache must beflushed The exact nature of the overhead of a thread or process contextswitch depends on the hardware in question
Inter-thread data transfer between threads running in separate cesses can also have an overhead because an area of data belonging tothe client must be mapped into the server’s address space
pro-How Can I Improve Performance?
For performance reasons, when transferring data between the client andserver, it is preferable, where possible, to transfer a large amount of data
in a single transaction rather than to perform a number of server accesses.However, this must still be balanced against the memory cost associatedwith storing and managing large blocks of request data
For example, Symbian OS components that frequently transfer data
to or from the filesystem generally do not use direct filesystem accessmethods such as RFile::Read() or RFile::Write() Instead, theytend to use the stream store or relational database APIs, which you can finddescribed in the system documentation These higher-level componentshave been optimized to access the file server efficiently When storingdata to file, they buffer it on the client side and pass it to the file server inone block, rather than passing individual chunks of data as it is received.Thus, taking the stream store for example, RWriteStream uses aclient-side buffer to hold the data it is passed, and only accesses the fileserver to write it to file when the buffer is full or if the owner of the streamcalls CommitL() Likewise, RReadStream pre-fills a buffer from thesource file when it is created When the stream owner wishes to accessdata from the file, the stream uses this buffer to retrieve the portions ofdata required, rather than calling the file server to access the file.When writing code which uses a server, it is always worth consideringhow to make your server access most efficient Take the file server, forexample: while there are functions to acquire individual directory entries
in the filesystem, it is often more efficient to read an entire set of entriesand scan them client-side, rather than call across the process boundary tothe file server multiple times to iterate through a set of directory entries
Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com
Trang 1511.15 How Many Outstanding Requests Can a Client
Make to a Server?
A client session with a server can only ever have a single synchronousrequest outstanding However, it can have up to 255 outstanding asyn-chronous requests The message slots which hold these requests are eitherallocated to a single session or acquired dynamically from a system-wide pool, according to the overload of RSessionBase::Create-Session()used to start the session See the discussion on RSession-Basein Section 11.4 for more details
11.16 Can Server Functionality Be Extended?
Server code can be extended by the use of plug-ins to offer differenttypes of service A good example of this is the Symbian OS file server,which can be extended at runtime to support different types of filesystemplug-in The core Symbian OS filesystem provides support for local media(ROM, RAM and CF card) using a VFAT filing system, implemented as
a plug-in, ELocal.fsy Other filesystems may be added, for example
to support a remote filesystem over a network or encryption of filedata before it is stored These file system plug-ins may be installed anduninstalled dynamically; in the client-side file server session class, RFs,you’ll see a set of functions for this purpose (FileSystemName(),AddFileSystem(), RemoveFileSystem(), MountFileSystem()and DismountFileSystem())
The extension code should be implemented as a polymorphic DLL(targettype fsy) and must conform to the fsy plug-in interfacedefined by Symbian OS More information about the use of frameworkand plug-in code in Symbian OS, and polymorphic DLLs, can be found
in Chapter 13
Since they normally run in the same thread as the server, and areoften called directly from CServer::RunL(), it is important to notethat installable server extension plug-in modules must not have a negativeimpact on the performance or runtime stability of the server
11.17 Example Code
Finally, here is an example of how a server may be accessed and used
It illustrates how a client thread creates a session with the Symbian OSfile server The file server session class, RFs, is defined in f32file.h,and to use the file server client-side implementation you must linkagainst efsrv.lib
Trang 16SUMMARY 187
Having successfully created the session and made it leave-safe usingthe cleanup stack (as described in Chapter 3), the sample code sub-mits a request to the file server, using RFs::Delete() This func-tion wraps the single descriptor parameter and passes it to the syn-chronous overload of RSessionBase::SendReceive() Followingthis, it creates an RFile subsession of the RFs session, by callingRFile::Create() It then calls RFile::Read() on the subses-sion, which submits a request to the file server by wrapping a call toRSubSessionBase::SendReceive(), passing in the descriptorparameter that identifies the buffer which will receive data read fromthe file
// Closes the subsession in the event of a leave CleanupClosePushL(file);
• The basics of the client–server framework and why it is used to shareaccess to system resources and protect their integrity
• The thread model for a client–server implementation The client andserver run in separate threads and often the server runs in a separateprocess; this isolates the system resource within a separate addressspace and protects it from potential misuse Symbian OS threads andprocesses are discussed in Chapter 10
Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com
Trang 17• The mechanism by which data is transferred between the clientand server, using inter-thread data transfer This uses inter-processcommunication (IPC) when the client and server run in differentprocesses, and there are potential runtime overheads associated withIPC data transfer.
• The main classes which make up the Symbian OS client–serverframework (RSessionBase, C(Sharable)Session, CServer,DSession, RMessage and RSubSessionBase), their main roles,features, fundamental methods and interactions
• Server startup (which is examined in more detail in the next chapter)and shutdown, either when all clients have disconnected normally or
as a result of the death of either the client or server
• The overheads associated with using a client–server architecture,such as the number of kernel resources consumed by having multipleopen sessions with a server, and the potential impact of using activeobjects with lengthy RunL() event handlers within the server
• Example code using F32, the file server, as an example of a typicalSymbian OS client–server model
The following chapter uses a detailed code example to illustrate a ical server, its client-side implementation, and its use by a calling client
Trang 18Capture the oxen of Geryon Take golden apples from the garden of Hesperides Bring Cerberus, the three-headed dog of the underworld, to the surface
The Twelve Labors of Hercules
This chapter works through the code for an example client and server toillustrate the main points of the Symbian OS client–server architecture,which I discussed in detail in Chapter 11 This chapter will be of particularinterest if you plan to implement your own server, or if you want to knowmore about how a client’s request to a server is transferred and handled.The code examines the typical features of a client–server implementa-tion using a transient server, which is started by its first client connectionand terminates when its last outstanding client session closes, to save sys-tem resources I’ll take the main elements of client–server code in turn anddiscuss the most important sections of each You can find the entire set ofsample code on the Symbian Press website (www.symbian.com/books).The bootstrap code used by a client to start a server can be quite complexand you may find it helps to download this example and step through thecode to follow how it works
As in the previous chapter, I discuss the client–server model only forSymbian OS releases up to and including v7.0s (the code samples inthis chapter use the client–server APIs from Symbian OS v7.0) Some of
Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com
Trang 19the APIs have changed from Symbian OS 8.0 onwards and, although theconcepts are generally the same, I’ve decided to concentrate solely on thereleases available at the time of going to press, rather than confuse matters.Client–server code can be notoriously complicated, so I have keptthe services provided by the server as simple as possible This comes,perhaps, at the expense of making the example code rather contrived; myclient–server example provides a software representation of the twelvelabors of the Greek hero Hercules.1 For each labor, I’ve exported afunction from a client-side implementation class, RHerculesSession.These functions send a request to the server to perform the necessaryheroic activity The client-side implementation is delivered as a sharedlibrary DLL (client.dll) – callers wishing to use the functionalityprovided by server should link to this The server code itself is built into
a separate EPOCEXE component (shared library DLLs and targettypeEPOCEXEare discussed in Chapter 13)
12.1 Client–Server Request Codes
A set of enumerated values is used to identify which service the clientrequests from the server These values are quite straightforward and aredefined as follows:
enum THerculeanLabors {
ESlayNemeanLion, ESlayHydra, ECaptureCeryneianHind, ESlayErymanthianBoar, ECleanAugeanStables, ESlayStymphalianBirds, ECaptureCretanBull, ECaptureMaresOfDiomedes, EObtainGirdleOfHippolyta, ECaptureOxenOfGeryon, ETakeGoldenApplesOfHesperides, ECaptureCerberus,
ECancelCleanAugeanStables, ECancelSlayStymphalianBirds };
Later in the chapter you’ll see these shared request ”opcodes” passed
to an overload of RSessionBase::SendReceive() on the client sideand stored in the corresponding server-side RMessage object (whichrepresents the client request) to identify which service the client hasrequested
1 If nothing else, this chapter will prepare you well for a pub quiz question about the Herculean labors.
Trang 20CLIENT BOILERPLATE CODE 191
12.2 Client Boilerplate Code
Much of the client-side implementation is made up of the API used
by callers to submit requests to the server This API is exported byRHerculesSession, which derives from RSessionBase Each ofthe request methods passes the associated opcode, and any param-eter data, to the server via a call to the base class methodRSessionBase::SendReceive(), using the synchronous or asyn-chronous overload as appropriate
Here is the definition of the main client-side class (I’ve shown only six
of the Herculean labor request methods):
// Forward declarations – the actual class declarations must be // accessible to both client and server code
IMPORT_C TInt SlayNemeanLion(const TDesC8& aDes, TInt aVal);
IMPORT_C TInt SlayHydra(THydraData& aData);
IMPORT_C TInt CaptureCeryneianHind(TInt& aCaptureCount);
IMPORT_C TInt SlayErymanthianBoar(const CHerculesData& aData);
IMPORT_C void CleanAugeanStables(TRequestStatus& aStatus);
IMPORT_C void CancelCleanAugeanStables();
IMPORT_C void SlayStymphalianBirds(TInt aCount, TDes8& aData, TRequestStatus& aStatus);
IMPORT_C void CancelSlayStymphalianBirds();
};
I’ve included a range of parameter input, and implemented chronous and asynchronous functions for illustration purposes Here arethe implementations of the request submission methods:
syn-EXPORT_C TInt RHerculesSession::SlayNemeanLion(const TDesC8& aDes, TInt aVal)
{ const TAny* p[KMaxMessageArguments];