Symbian OS Explained - Effective C++ Programming For Smartphones (2005) (779885), страница 47
Текст из файла (страница 47)
The server has an integer value,count, which represents the number of hinds captured. It ”descriptorizes”this value using a TPckgC and calls RMessage::WriteL() to makean inter-thread data transfer into the client thread.Earlier, I discussed in detail how the client submitted custom objectsto the server, such as those of T or C classes. I described how anobject of class THydraData was marshaled into a descriptor using theTPckg class, and in CHerculesSession::SlayHydraL() you seewhat happens on the other side of the client–server boundary.
Theserver instantiates its own THydraData object, wraps it in a TPckgdescriptor and then ”reconstitutes” it by reading into it the descriptorpassed by the client. Having done so, the server performs the necessaryprocessing which modifies the object. It writes the changes back to theclient using RMessage::WriteL(). In a similar manner, CHerculesSession::SlayErymanthianBoarL() shows how a server receivesa ”streamed” CBase-derived object in a descriptor and instantiates itsown copy using the appropriate NewLC() method. This object can thenbe passed as a parameter to the appropriate internal handling function.While most of the request handler methods shown are synchronous,CleanAugeanStables() and SlayStymphalianBirdsL() are asynchronous.
The server retrieves any parameters passed from the clientand passes them to an active object which is responsible for submittingrequests to an asynchronous service provider and handling their completion events. To avoid complicating the code example I haven’t shown theactive object class here, but I discuss active objects fully in Chapters 8and 9.
The active object class must be passed a means to access theRMessage associated with the client request, which it will use to callComplete() on the client when the request has been fulfilled by theasynchronous service provider. Since it only uses the RMessage to complete the client, it is unnecessary for this class to hold a copy of the entireobject.
Commonly, the RMessagePtr class is used to make a copy ofthe client’s thread handle from the RMessage, and the RMessagePtrobject is then used to notify the client of the request’s completion. ClassRMessagePtr is defined in e32std.h.SERVER SHUTDOWN213Incidentally, a constant reference to the RMessage associated withthe request is passed into each of the request handler methods butit may, alternatively, be retrieved by the handler methods by calling CSharableSession::Message(). However, the asynchronousrequests must store a copy of the RMessage object, because the sessionmay be processing another, different, request message by the time theasynchronous request completes and is handled.12.6 Server ShutdownThe timer class which manages server shutdown is shown below:const TInt KShutdownDelay=200000; // approx 2 secondsclass CShutdown : public CTimer{public:inline CShutdown();inline void ConstructL();inline void Start();private:void RunL();};inline CShutdown::CShutdown(): CTimer(-1) {CActiveScheduler::Add(this);}inline void CShutdown::ConstructL(){CTimer::ConstructL();}inline void CShutdown::Start(){After(KShutdownDelay);}void CShutdown::RunL(){// Initiates server exit when the timer expiresCActiveScheduler::Stop();}The CServer-derived object owns a CShutdown object.
As I described above, the server reference-counts its connected client sessions.The shutdown timer object is started when there are no sessions connectedto the server, although it is canceled if a session connects before the timerexpires. When the timeout completes, the timer’s event handler callsCActiveScheduler::Stop() to terminate the server’s wait loop anddestroy the server. The timeout is used to delay shutdown and preventexcessive startup/shutdown churn caused by client connections whichdo not quite overlap. The server’s shutdown timeout is defined byKShutdownDelay, which is set to 2 seconds.21412.7THE CLIENT–SERVER FRAMEWORK IN PRACTICEAccessing the ServerFinally, for reference, here is an example of how the Hercules server maybe accessed and used by a client.
The client-side RHerculesSessionclass is used to connect a session to the server and wrap the caller’sparameter data as appropriate, before passing it to the server.void TestClientServerL(){__UHEAP_MARK; // Checks for memory leaks (see Chapter 17)RHerculesSession session;User::LeaveIfError(session.Connect());CleanupClosePushL(session); // Closes the session if it leaves_LIT8(KLionDes, "NemeanLion");User::LeaveIfError(session.SlayNemeanLion(KLionDes, 1));TVersion version(1,0,0);THydraData hydraData;hydraData.iHydraVersion = version;hydraData.iHeadCount = 9;User::LeaveIfError(session.SlayHydra(hydraData));...
// Checks hydraData, which was modified by the serverTInt count;User::LeaveIfError(session.CaptureCeryneianHind(count));... // Checks count which was set by the serverCHerculesData* data =CHerculesData::NewLC(_L8("test1"), _L8("test2"), 1);User::LeaveIfError(session.SlayErymanthianBoar(*data));TRequestStatus status;session.CleanAugeanStables(status);User::WaitForRequest(status);// Server reads this data and updates itTBuf8<12> myBuf(_L8("testdata"));session.SlayStymphalianBirds(3, myBuf, status);User::WaitForRequest(status);...
// Inspects the contents of myBuf, modified by the serverCleanupStack::PopAndDestroy(2, &session); // data, session__UHEAP_MARKEND;}12.8SummaryThis chapter examined code for a typical client–server implementation,using a simplistic example to avoid introducing ”accidental complexity”.It is intended for those wishing to implement a server and its client-sideaccess code, and to illustrate how the Symbian OS client–server architecture works in practice, reinforcing the theory described in Chapter 11.SUMMARY215The example is a transient server that runs in a separate process fromits clients, with the client-side implementation in a separate DLL.
Thechapter discusses best practice in the following areas of code:• the use of ”opcodes” to identify a client request• a typical client-side RSessionBase-derived class and its ”boilerplate” code to submit requests to the server. The discussion includeddetails of how to submit different types of parameter data to the server:• simple built-in types• descriptors• flat data (such as that contained in a struct or an object of aT class)• more complex objects, which do not have a fixed length or whichcontain pointers to other objects (e.g. an object of a C class).• how to implement client-side code to start the server (which forEKA1 is different depending on whether the server is running onthe Windows emulator or target hardware) and how to connect tothe server• server-side bootstrap code• the fundamental server classes, deriving from CServer andCSharableSession, including examples of request-handling methods (for both synchronous and asynchronous requests), server-sideunpacking of parameter data passed from the client, and an exampleof how data can be passed back to the client• the mechanism used by a transient server to reference-count itsconnected client sessions and shut itself down, after a brief timeout,when all its clients have disconnected• the implementation of a typical calling client that instantiates an objectof the RSessionBase-derived client class and submits requests tothe server.This chapter also listed the twelve labors of Hercules, which the readermay, or may not, wish to commit to memory.13Binary TypesOh Lord, forgive the misprintsLast words of Andrew Bradford, American PublisherThe executable code of any C++ component on Symbian OS is deliveredas a binary package.
There are two particular types discussed in thischapter: packages which are launched as a new process (.exe) andthose that run inside an existing process, dynamically linked libraries(.dll). Note that I use the term ”executable” in this context to refer toany binary code which may execute, as opposed to a .exe exclusively.13.1 Symbian OS EXEsOn the Windows emulator Symbian OS runs within a single Win32process. If you look at Task Manager on Windows when the emulatoris running, you’ll see the process, EPOC.exe. Within that process, eachSymbian OS EXE is emulated within a separate thread.On a phone handset running Symbian OS, commonly known as”target hardware”, each EXE is launched in a separate, new process.Each process has a single main thread that invokes the sole entry pointfunction, E32Main().On target hardware, executable code can either be built onto thephone in Read-Only Memory (ROM) when the phone is in the factory orinstalled on the phone at a later stage – either into the phone’s internalstorage or onto removable storage media such as a Memory Stick orMMC.
It’s a simplification, but you can generally think of ROM-basedEXEs as being executed directly in-place from the ROM. This means thatprogram code and read-only data (such as literal descriptors) are readdirectly from the ROM, and the component is only allocated a separatedata area in RAM for its read/write data.If an EXE is installed, rather than built into the ROM, it executes entirelyfrom RAM and has an area allocated for program code and read-only218BINARY TYPESstatic data, and a separate area for read/write static data.