diff -r ebc84c812384 -r 46218c8b8afa Symbian3/PDK/Source/GUID-51621C76-17B5-5829-B4EC-86B453442CDC.dita --- a/Symbian3/PDK/Source/GUID-51621C76-17B5-5829-B4EC-86B453442CDC.dita Thu Mar 11 15:24:26 2010 +0000 +++ b/Symbian3/PDK/Source/GUID-51621C76-17B5-5829-B4EC-86B453442CDC.dita Thu Mar 11 18:02:22 2010 +0000 @@ -1,184 +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.

  • -
+ + + + + +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