- •Contents
- •1.1 Fundamental Types
- •1.2 T Classes
- •1.3 C Classes
- •1.4 R Classes
- •1.5 M Classes
- •1.6 Static Classes
- •1.7 Buyer Beware
- •1.8 Summary
- •2 Leaves: Symbian OS Exceptions
- •2.1 Leaving Functions
- •2.3 Constructors and Destructors
- •2.4 Working with Leaving Functions
- •2.5 Trapping a Leave Using TRAP and TRAPD
- •2.6 LeaveScan
- •2.7 Summary
- •3 The Cleanup Stack
- •3.1 Using the Cleanup Stack
- •3.2 How Does the Cleanup Stack Work?
- •3.4 Using TCleanupItem for Customized Cleanup
- •3.5 Portability
- •3.6 An Incidental Note on the Use of Casts
- •3.7 Summary
- •5 Descriptors: Symbian OS Strings
- •5.3 Pointer Descriptors
- •5.4 Stack-Based Buffer Descriptors
- •5.5 Heap-Based Buffer Descriptors
- •5.6 Literal Descriptors
- •5.7 Summary
- •6 Good Descriptor Style
- •6.1 Descriptors as Parameters and Return Types
- •6.2 Common Descriptor Methods
- •6.3 The Use of HBufC Heap Descriptors
- •6.4 Externalizing and Internalizing Descriptors
- •6.5 The Overuse of TFileName
- •6.6 Useful Classes for Descriptor Manipulation
- •6.7 Summary
- •7 Dynamic Arrays and Buffers
- •7.1 CArrayX Classes
- •7.3 Why Use RArray Instead of CArrayX?
- •7.4 Dynamic Descriptor Arrays
- •7.5 Fixed-Length Arrays
- •7.6 Dynamic Buffers
- •7.7 Summary
- •8.1 Multitasking Basics
- •8.2 Event-Driven Multitasking
- •8.3 Working with Active Objects
- •8.4 Example Code
- •8.5 Threads Without an Active Scheduler
- •8.6 Application Code and Active Objects
- •8.7 Summary
- •9 Active Objects under the Hood
- •9.1 Active Object Basics
- •9.2 Responsibilities of an Active Object
- •9.3 Responsibilities of an Asynchronous Service Provider
- •9.4 Responsibilities of the Active Scheduler
- •9.5 Starting the Active Scheduler
- •9.6 Nesting the Active Scheduler
- •9.7 Extending the Active Scheduler
- •9.8 Cancellation
- •9.9 Request Completion
- •9.10 State Machines
- •9.11 Long-Running Tasks
- •9.14 Common Mistakes
- •9.15 Summary
- •10 Symbian OS Threads and Processes
- •10.2 Thread Priorities
- •10.3 Stopping a Running Thread
- •10.5 Exception Handling
- •10.6 Processes
- •10.7 Summary
- •11.2 How Do the Client and Server Fit Together?
- •11.3 How Do the Client and Server Communicate?
- •11.5 How Do Synchronous and Asynchronous Requests Differ?
- •11.6 How Is a Server Started?
- •11.7 How Many Connections Can a Client Have?
- •11.8 What Happens When a Client Disconnects?
- •11.9 What Happens If a Client Dies?
- •11.10 What Happens If a Server Dies?
- •11.15 How Many Outstanding Requests Can a Client Make to a Server?
- •11.16 Can Server Functionality Be Extended?
- •11.17 Example Code
- •11.18 Summary
- •12.2 Client Boilerplate Code
- •12.3 Starting the Server and Connecting to It from the Client
- •12.4 Server Startup Code
- •12.5 Server Classes
- •12.6 Server Shutdown
- •12.7 Accessing the Server
- •12.8 Summary
- •13 Binary Types
- •13.1 Symbian OS EXEs
- •13.2 Symbian OS DLLs
- •13.3 Writable Static Data
- •13.4 Thread-Local Storage
- •13.5 The DLL Loader
- •13.6 UIDs
- •13.8 Summary
- •14 ECOM
- •14.1 ECOM Architecture
- •14.2 Features of an ECOM Interface
- •14.3 Factory Methods
- •14.4 Implementing an ECOM Interface
- •14.5 Resource Files
- •14.6 Example Client Code
- •14.7 Summary
- •15 Panics
- •15.2 Good Panic Style
- •15.3 Symbian OS Panic Categories
- •15.4 Panicking Another Thread
- •15.5 Faults, Leaves and Panics
- •15.6 Summary
- •16 Bug Detection Using Assertions
- •16.3 Summary
- •17 Debug Macros and Test Classes
- •17.1 Heap-Checking Macros
- •17.2 Object Invariance Macros
- •17.3 Console Tests Using RTest
- •17.4 Summary
- •18 Compatibility
- •18.1 Forward and Backward Compatibility
- •18.2 Source Compatibility
- •18.3 Binary Compatibility
- •18.4 Preventing Compatibility Breaks
- •18.5 What Can I Change Without Breaking Binary Compatibility?
- •18.6 Best Practice: Planning for Future Changes
- •18.7 Compatibility and the Symbian OS Class Types
- •18.8 Summary
- •19 Thin Templates
- •20.1 Class Layout
- •20.3 Parameters and Return Values
- •20.4 Member Data and Functional Abstraction
- •20.5 Choosing Class, Method and Parameter Names
- •20.7 Summary
- •21 Good Code Style
- •21.1 Reduce the Size of Program Code
- •21.2 Use Heap Memory Carefully
- •21.3 Use Stack Memory Carefully
- •21.5 Optimize Late
- •21.6 Summary
- •Glossary
- •Bibliography and Online Resources
- •Index
186 |
THE CLIENT–SERVER FRAMEWORK IN THEORY |
11.15How Many Outstanding Requests Can a Client Make to a Server?
A client session with a server can only ever have a single synchronous request outstanding. However, it can have up to 255 outstanding asynchronous requests. The message slots which hold these requests are either allocated to a single session or acquired dynamically from a systemwide pool, according to the overload of RSessionBase::CreateSession() used to start the session. See the discussion on RSessionBase in Section 11.4 for more details.
11.16Can Server Functionality Be Extended?
Server code can be extended by the use of plug-ins to offer different types of service. A good example of this is the Symbian OS file server, which can be extended at runtime to support different types of filesystem plug-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 file data before it is stored. These file system plug-ins may be installed and uninstalled 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 interface defined by Symbian OS. More information about the use of framework and 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 are often called directly from CServer::RunL(), it is important to note that installable server extension plug-in modules must not have a negative impact on the performance or runtime stability of the server.
11.17Example 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 OS file server. The file server session class, RFs, is defined in f32file.h, and to use the file server client-side implementation you must link against efsrv.lib.
SUMMARY |
187 |
Having successfully created the session and made it leave-safe using the cleanup stack (as described in Chapter 3), the sample code submits a request to the file server, using RFs::Delete(). This function wraps the single descriptor parameter and passes it to the synchronous overload of RSessionBase::SendReceive(). Following this, it creates an RFile subsession of the RFs session, by calling
RFile::Create(). It then calls RFile::Read() on the subsession, which submits a request to the file server by wrapping a call to
RSubSessionBase::SendReceive(), passing in the descriptor parameter that identifies the buffer which will receive data read from the file.
RFs fs;
User::LeaveIfError(fs.Connect());
CleanupClosePushL(fs); // Closes the session in the event of a leave
_LIT(KClangerIni, "c:\\clanger.ini");
// Submits a delete request to the server User::LeaveIfError(fs.Delete(KClangerIni));
RFile file; // A subsession
User::LeaveIfError(file.Create(fs, KClangerIni,
EFileRead|EFileWrite|EFileShareExclusive)); // Closes the subsession in the event of a leave CleanupClosePushL(file);
TBuf8<32> buf;
// Submits a request using the subsession User::LeaveIfError(file.Read(buf)); CleanupStack::PopAndDestroy(2, &fs); // file, fs
11.18Summary
This chapter explored the theory behind the Symbian OS client–server framework. It is quite a complex subject, so the chapter was split into a number of short sections to allow it to be read at several different levels, depending on whether the information is required to use a server or to write one. The sections covered the following:
•The basics of the client–server framework and why it is used to share access to system resources and protect their integrity.
•The thread model for a client–server implementation. The client and server run in separate threads and often the server runs in a separate process; this isolates the system resource within a separate address space and protects it from potential misuse. Symbian OS threads and processes are discussed in Chapter 10.
188 |
THE CLIENT–SERVER FRAMEWORK IN THEORY |
•The mechanism by which data is transferred between the client and server, using inter-thread data transfer. This uses inter-process communication (IPC) when the client and server run in different processes, and there are potential runtime overheads associated with IPC data transfer.
•The main classes which make up the Symbian OS client–server framework (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 multiple open sessions with a server, and the potential impact of using active objects with lengthy RunL() event handlers within the server.
•Example code using F32, the file server, as an example of a typical Symbian OS client–server model.
The following chapter uses a detailed code example to illustrate a typical server, its client-side implementation, and its use by a calling client.
12
The Client–Server Framework
in Practice
Kill the lion of Nemea Kill the nine-headed Hydra Capture the Ceryneian Hind
Kill the wild boar of Erymanthus Clean the stables of King Augeas Kill the birds of Stymphalis Capture the wild bull of Crete
Capture the man-eating mares of Diomedes Obtain the girdle of Hippolyta, Queen of the Amazons
Capture 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 to illustrate the main points of the Symbian OS client–server architecture, which I discussed in detail in Chapter 11. This chapter will be of particular interest if you plan to implement your own server, or if you want to know more about how a client’s request to a server is transferred and handled.
The code examines the typical features of a client–server implementation using a transient server, which is started by its first client connection and terminates when its last outstanding client session closes, to save system resources. I’ll take the main elements of client–server code in turn and discuss the most important sections of each. You can find the entire set of sample code on the Symbian Press website (www.symbian.com/books). The bootstrap code used by a client to start a server can be quite complex and you may find it helps to download this example and step through the code to follow how it works.
As in the previous chapter, I discuss the client–server model only for Symbian OS releases up to and including v7.0s (the code samples in this chapter use the client–server APIs from Symbian OS v7.0). Some of
190 |
THE CLIENT–SERVER FRAMEWORK IN PRACTICE |
the APIs have changed from Symbian OS 8.0 onwards and, although the concepts are generally the same, I’ve decided to concentrate solely on the releases available at the time of going to press, rather than confuse matters.
Client–server code can be notoriously complicated, so I have kept the services provided by the server as simple as possible. This comes, perhaps, at the expense of making the example code rather contrived; my client–server example provides a software representation of the twelve labors of the Greek hero Hercules.1 For each labor, I’ve exported a function from a client-side implementation class, RHerculesSession. These functions send a request to the server to perform the necessary heroic activity. The client-side implementation is delivered as a shared library DLL (client.dll) – callers wishing to use the functionality provided by server should link to this. The server code itself is built into a separate EPOCEXE component (shared library DLLs and targettype EPOCEXE are discussed in Chapter 13).
12.1Client–Server Request Codes
A set of enumerated values is used to identify which service the client requests from the server. These values are quite straightforward and are defined 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 side and stored in the corresponding server-side RMessage object (which represents the client request) to identify which service the client has requested.
1 If nothing else, this chapter will prepare you well for a pub quiz question about the Herculean labors.