diff -r 000000000000 -r 89d6a7a84779 Symbian3/SDK/Source/GUID-51621C76-17B5-5829-B4EC-86B453442CDC.dita --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Symbian3/SDK/Source/GUID-51621C76-17B5-5829-B4EC-86B453442CDC.dita Thu Jan 21 18:18:20 2010 +0000 @@ -0,0 +1,184 @@ + + + + + +How +to implement a simple server interfaceProvides code snippets to help you to implement a simple server +interface. +
Handling asynchronous requests

The implementation +of a server requires a class derived from CServer2. This +is the active object base class responsible for handling the asynchronous +requests from the client program.

Construction and initialisation

An +instance of the CServer2 derived class is, typically, created +by the server's thread function. As an active object, it needs a priority +and this is passed as a parameter to the constructor. The choice of priority +value depends on the server's design. If the server can, ultimately, have +more than one active object, then it may be important for the CServer2 active +object to have the highest priority.

The server can now be started. +This is a code fragment taken from the example that can be found at ...\examples\Base\IPC\ClientServer\complex.

CCountServServer *pS=new CCountServServer(EPriorityStandard); +__ASSERT_ALWAYS(pS!=NULL,CCountServServer::PanicServer(ESvrCreateServer)); +... + + // Start the server +TInt err = pS->Start(KCountServerName); +if (err != KErrNone) + { + CCountServServer::PanicServer(ESvrStartServer); + }

The function CServer2::Start() adds +the CServer2 active object to the active scheduler and issues +the first request for messages. The server is now waiting for messages.

As +with all active objects, the completion of requests for messages is handled +by the CServer2::RunL() protected member function.

Handling requests

A request for a connection by a client thread +results in the creation of a new session. The request for a connection results +in a call by the client/server framework to the CServer2::NewSessionL() function. +A derived class must provide an implementation - creating and initialising +an instance of a CSession2 derived class. The framework +takes this newly created session object to the server's queue.

For +a non sharable session, requests for disconnection by a client thread cause +the relevant CSession2 object to be deleted. The CSession2 destructor +should perform appropriate cleanup.

Any other message is passed to CSession2::ServiceL(). +This function must be implemented by a derived class.

+
Server side session representation

The base class CSession2 represents +a client's session on the server side. This class provides the standard session +behaviour. A class derived from CSession2 must be defined +and implemented. The following class definition, taken from the example that +can be found at: ...\examples\Base\IPC\ClientServer\simple, +is typical:

class CCountServSession : public CSession2 + { +public: + CCountServSession(); + + //service request + void ServiceL(const RMessage2& aMessage); + void DispatchMessageL(const RMessage2& aMessage); + + // services available to initialize/increase/decrease/reset and + // return the counter value. + void SetFromStringL(const RMessage2& aMessage); + void Increase(); + void Decrease(); + void IncreaseBy(const RMessage2& aMessage); + void DecreaseBy(const RMessage2& aMessage); + void CounterValue(const RMessage2& aMessage); + void Reset(); + +protected: + // panic the client + void PanicClient(const RMessage2& aMessage,TInt aPanic) const; + +private: + TInt iCount; + };

Note the following:

    +
  • The function ServiceL() is +called by the client/server framework to handle all messages except requests +to connect and disconnect.

  • +
  • ServiceL() calls DispatchMessageL() under +a trap harness.

  • +
  • DispatchMessageL() determines +the appropriate message service function to call by examining the operation +code of the current message. This is simply a mechanism to delegate the handling +of different request types.

  • +
  • The class provides message +service functions: Increase(), IncreaseBy() etc. +to service specific messages from clients.

  • +
  • The function SetFromStringL() needs +a string specified by the client and therefore needs to read data from the +client address space.

  • +

ServiceL()

This +is implemented as follows:

void CCountServSession::ServiceL(const RMessage2& aMessage) + { + TRAPD(err,DispatchMessageL(aMessage)); + aMessage.Complete(err); + }

After calling the appropriate service function via DispatchMessageL(), +the asynchronous request is completed with aMessage.Complete() which +passes the completion code back to the client.

DispatchMessageL()

This is implemented as follows:

void CCountServSession::DispatchMessageL(const RMessage2& aMessage) + { + switch (aMessage.Function()) + { + case ECountServSetFromString: + SetFromStringL(aMessage); + return; + case ECountServIncrease: + Increase(); + return; + case ECountServIncreaseBy: + IncreaseBy(aMessage); + return; + ... + case ECountServValue: + CounterValue(aMessage); + return; + ... + default: + PanicClient(aMessage,EBadRequest); + return; + } + }

IncreaseBy()

This message service function is implemented as follows:

void CCountServSession::IncreaseBy(const RMessage2& aMessage) + { + iCount = iCount + aMessage.Int0(); + }

Note that we need to pass the message object to the function. +The Int0() function is used to get the integer specified +in the client call - the '0' on the end of the function name indicates that +the integer is the first parameter in the set passed across from the client.

SetFromStringL()

This message service function is implemented +as follows:

void CCountServSession::SetFromStringL(const RMessage2& aMessage) + { + // length of passed descriptor (1st parameter passed from client) + TInt deslen = aMessage.GetDesLength(0); + + // Passed data will be saved in this descriptor. + RBuf buffer; + + // Max length set to the value of "deslen", but current length is zero + buffer.CreateL(deslen); + + // Do the right cleanup if anything subsequently goes wrong + buffer.CleanupClosePushL(); + + // Copy the client's descriptor data into our buffer. + aMessage.ReadL(0,buffer,0); + + // Now do a validation to make sure that the string only has digits + if (buffer.Length() == 0) + { + User::Leave(ENonNumericString); + } + ... + // Do rest of work to convert from + // string to integer, and assign.

RMessage::ReadL() reads +the descriptor from the client address space as specified by the first argument +in the message, and copies the data into the descriptor specified as its second +argument. A basic test is done to make sure there data is supplied.

CounterValue()

This is implemented as follows:

void CCountServSession::CounterValue(const RMessage2& aMessage) + { + TPckgBuf<TInt> p(iCount); + aMessage.WriteL(0,p); + }

It writes data back to a descriptor in the client address +space. The corresponding client request is:

TInt RCountServSession::CounterValue() + { + TInt res=0; + TckgBuf<TInt> pckg; + + // Note that TPckgBuf is of type TDes8 + TIpcArgs args(&pckg); + SendReceive(ECountServValue, args); + + // Extract the value returned from the server. + res = pckg(); + return res; + }

Notes

    +
  • The TInt is +packaged into a descriptor before being passed to the server. The packaging +mechanism is known as package buffer.

  • +
  • The write operation +copies the descriptor, i.e. the package buffer containing the integer value, +back to the descriptor in the client address space. Note that the zero specified +in aMessage.WriteL(0,p); means that the argument referred +to is the first in the list passed across from the client side via the TIpcArgs object.

  • +
+
\ No newline at end of file