Symbian3/SDK/Source/GUID-51621C76-17B5-5829-B4EC-86B453442CDC.dita
changeset 0 89d6a7a84779
equal deleted inserted replaced
-1:000000000000 0:89d6a7a84779
       
     1 <?xml version="1.0" encoding="utf-8"?>
       
     2 <!-- Copyright (c) 2007-2010 Nokia Corporation and/or its subsidiary(-ies) All rights reserved. -->
       
     3 <!-- This component and the accompanying materials are made available under the terms of the License 
       
     4 "Eclipse Public License v1.0" which accompanies this distribution, 
       
     5 and is available at the URL "http://www.eclipse.org/legal/epl-v10.html". -->
       
     6 <!-- Initial Contributors:
       
     7     Nokia Corporation - initial contribution.
       
     8 Contributors: 
       
     9 -->
       
    10 <!DOCTYPE concept
       
    11   PUBLIC "-//OASIS//DTD DITA Concept//EN" "concept.dtd">
       
    12 <concept id="GUID-51621C76-17B5-5829-B4EC-86B453442CDC" xml:lang="en"><title>How
       
    13 to implement a simple server interface</title><shortdesc>Provides code snippets to help you to implement a simple server
       
    14 interface.</shortdesc><prolog><metadata><keywords/></metadata></prolog><conbody>
       
    15 <section id="GUID-2720017E-2EDF-4DB5-81E9-2A75E434BDE3"><title>Handling asynchronous requests</title> <p>The implementation
       
    16 of a server requires a class derived from <codeph>CServer2</codeph>. This
       
    17 is the <i>active object</i> base class responsible for handling the asynchronous
       
    18 requests from the client program. </p> <p><b>Construction and initialisation</b> </p> <p>An
       
    19 instance of the <codeph>CServer2</codeph> derived class is, typically, created
       
    20 by the server's thread function. As an active object, it needs a priority
       
    21 and this is passed as a parameter to the constructor. The choice of priority
       
    22 value depends on the server's design. If the server can, ultimately, have
       
    23 more than one active object, then it may be important for the <codeph>CServer2</codeph> active
       
    24 object to have the highest priority. </p> <p>The server can now be started.
       
    25 This is a code fragment taken from the example that can be found at <filepath>...\examples\Base\IPC\ClientServer\complex</filepath>. </p> <codeblock id="GUID-6D887396-920C-5B5B-B58E-6700371DB31C" xml:space="preserve">CCountServServer *pS=new CCountServServer(EPriorityStandard);
       
    26 __ASSERT_ALWAYS(pS!=NULL,CCountServServer::PanicServer(ESvrCreateServer));
       
    27 ...
       
    28       
       
    29     // Start the server
       
    30 TInt err = pS-&gt;Start(KCountServerName);
       
    31 if (err != KErrNone)
       
    32     {
       
    33     CCountServServer::PanicServer(ESvrStartServer);
       
    34     }</codeblock> <p>The function <codeph>CServer2::Start()</codeph> adds
       
    35 the <codeph>CServer2</codeph> active object to the active scheduler and issues
       
    36 the first request for messages. The server is now waiting for messages. </p> <p>As
       
    37 with all active objects, the completion of requests for messages is handled
       
    38 by the <codeph>CServer2::RunL()</codeph> protected member function. </p> <p><b>Handling requests</b> </p> <p>A request for a connection by a client thread
       
    39 results in the creation of a new session. The request for a connection results
       
    40 in a call by the client/server framework to the <xref href="GUID-8E316AC4-4676-301A-9A23-659E83AA1D1C.dita#GUID-8E316AC4-4676-301A-9A23-659E83AA1D1C/GUID-3260F745-3597-349A-9754-303DC020EF18"><apiname>CServer2::NewSessionL()</apiname></xref> function.
       
    41 A derived class must provide an implementation - creating and initialising
       
    42 an instance of a <xref href="GUID-D5A30C75-E22C-34E8-913B-7D2CA6AD5C51.dita"><apiname>CSession2</apiname></xref> derived class. The framework
       
    43 takes this newly created session object to the server's queue. </p> <p>For
       
    44 a non sharable session, requests for disconnection by a client thread cause
       
    45 the relevant <codeph>CSession2</codeph> object to be deleted. The <codeph>CSession2</codeph> destructor
       
    46 should perform appropriate cleanup. </p> <p>Any other message is passed to <codeph>CSession2::ServiceL()</codeph>.
       
    47 This function must be implemented by a derived class. </p> </section>
       
    48 <section id="GUID-2E5EB078-59D7-49B3-A32A-17AF0FBD3492"><title>Server side session representation</title> <p>The base class <codeph>CSession2</codeph> represents
       
    49 a client's session on the server side. This class provides the standard session
       
    50 behaviour. A class derived from <codeph>CSession2</codeph> must be defined
       
    51 and implemented. The following class definition, taken from the example that
       
    52 can be found at: <filepath>...\examples\Base\IPC\ClientServer\simple</filepath>,
       
    53 is typical: </p> <codeblock id="GUID-8DCCB062-2630-5C2E-A590-89208928E902" xml:space="preserve">class CCountServSession : public CSession2
       
    54     {
       
    55 public:
       
    56     CCountServSession();
       
    57 
       
    58       //service request
       
    59     void ServiceL(const RMessage2&amp; aMessage);
       
    60     void DispatchMessageL(const RMessage2&amp; aMessage);
       
    61 
       
    62       // services available to initialize/increase/decrease/reset and
       
    63       // return the counter value.
       
    64     void SetFromStringL(const RMessage2&amp; aMessage);
       
    65     void Increase();
       
    66     void Decrease();
       
    67     void IncreaseBy(const RMessage2&amp; aMessage);
       
    68     void DecreaseBy(const RMessage2&amp; aMessage);
       
    69     void CounterValue(const RMessage2&amp; aMessage);
       
    70     void Reset();
       
    71 
       
    72 protected:
       
    73         // panic the client
       
    74    void PanicClient(const RMessage2&amp; aMessage,TInt aPanic) const;
       
    75         
       
    76 private:
       
    77     TInt iCount;
       
    78     };</codeblock> <p>Note the following: </p> <ul>
       
    79 <li id="GUID-D3EE4EBA-47F3-5EC4-8487-A4DBD809D2B3"><p>The function <codeph>ServiceL()</codeph> is
       
    80 called by the client/server framework to handle all messages except requests
       
    81 to connect and disconnect. </p> </li>
       
    82 <li id="GUID-C4980BE1-D852-5AAE-8782-8C98D95BA102"><p> <codeph>ServiceL()</codeph> calls <codeph>DispatchMessageL()</codeph> under
       
    83 a trap harness. </p> </li>
       
    84 <li id="GUID-19A78104-9C7C-53C7-8328-F34E2CBCF857"><p> <codeph>DispatchMessageL()</codeph> determines
       
    85 the appropriate message service function to call by examining the operation
       
    86 code of the current message. This is simply a mechanism to delegate the handling
       
    87 of different request types. </p> </li>
       
    88 <li id="GUID-9A3F4396-8561-540D-BE0B-C674A14704AE"><p>The class provides message
       
    89 service functions: <codeph>Increase()</codeph>, <codeph>IncreaseBy()</codeph> etc.
       
    90 to service specific messages from clients. </p> </li>
       
    91 <li id="GUID-023BAF14-7588-5F25-B75C-8F1126D7749F"><p>The function <codeph>SetFromStringL()</codeph> needs
       
    92 a string specified by the client and therefore needs to read data from the
       
    93 client address space. </p> </li>
       
    94 </ul> <p><b>ServiceL()</b> </p> <p>This
       
    95 is implemented as follows: </p> <codeblock id="GUID-293D2833-3C1C-5B6E-AACF-B8EC20E0F7F9" xml:space="preserve">void CCountServSession::ServiceL(const RMessage2&amp; aMessage)
       
    96     {
       
    97     TRAPD(err,DispatchMessageL(aMessage));
       
    98     aMessage.Complete(err);
       
    99     }</codeblock> <p>After calling the appropriate service function via <codeph>DispatchMessageL()</codeph>,
       
   100 the asynchronous request is completed with <codeph>aMessage.Complete()</codeph> which
       
   101 passes the completion code back to the client. </p> <p><b>DispatchMessageL()</b> </p> <p>This is implemented as follows: </p> <codeblock id="GUID-14C3190C-921F-5C69-B0D0-7932C71B5ACF" xml:space="preserve">void CCountServSession::DispatchMessageL(const RMessage2&amp; aMessage)
       
   102     {
       
   103     switch (aMessage.Function())
       
   104         {
       
   105     case ECountServSetFromString:
       
   106         SetFromStringL(aMessage);
       
   107         return;
       
   108     case ECountServIncrease:
       
   109         Increase();
       
   110         return;
       
   111     case ECountServIncreaseBy:
       
   112         IncreaseBy(aMessage);
       
   113         return;
       
   114         ...
       
   115     case ECountServValue:
       
   116         CounterValue(aMessage);
       
   117         return;
       
   118     ...
       
   119     default:
       
   120         PanicClient(aMessage,EBadRequest);
       
   121         return;
       
   122         }
       
   123     }</codeblock> <p><b>IncreaseBy()</b> </p> <p>This message service function is implemented as follows: </p> <codeblock id="GUID-4516B089-F1D8-56BD-82CB-B7A1B0E98F0D" xml:space="preserve">void CCountServSession::IncreaseBy(const RMessage2&amp; aMessage)
       
   124     {
       
   125     iCount = iCount + aMessage.Int0(); 
       
   126     }</codeblock> <p>Note that we need to pass the message object to the function.
       
   127 The <codeph>Int0()</codeph> function is used to get the integer specified
       
   128 in the client call - the '0' on the end of the function name indicates that
       
   129 the integer is the first parameter in the set passed across from the client. </p> <p><b>SetFromStringL()</b> </p> <p>This message service function is implemented
       
   130 as follows: </p> <codeblock id="GUID-2BC55BC9-6AE1-5462-A6EE-6767F8EE19C7" xml:space="preserve">void CCountServSession::SetFromStringL(const RMessage2&amp; aMessage)
       
   131     {
       
   132          // length of passed descriptor (1st parameter passed from client)
       
   133     TInt deslen = aMessage.GetDesLength(0);
       
   134     
       
   135       // Passed data will be saved in this descriptor.
       
   136     RBuf buffer;
       
   137       
       
   138       // Max length set to the value of "deslen", but current length is zero
       
   139     buffer.CreateL(deslen);
       
   140       
       
   141       // Do the right cleanup if anything subsequently goes wrong
       
   142     buffer.CleanupClosePushL();
       
   143     
       
   144       // Copy the client's descriptor data into our buffer.
       
   145     aMessage.ReadL(0,buffer,0);
       
   146     
       
   147       // Now do a validation to make sure that the string only has digits
       
   148     if (buffer.Length() == 0)
       
   149         {
       
   150         User::Leave(ENonNumericString);
       
   151         }
       
   152     ...
       
   153       // Do rest of work to convert from 
       
   154       // string to integer, and assign.</codeblock> <p> <codeph>RMessage::ReadL()</codeph> reads
       
   155 the descriptor from the client address space as specified by the first argument
       
   156 in the message, and copies the data into the descriptor specified as its second
       
   157 argument. A basic test is done to make sure there data is supplied. </p> <p><b>CounterValue()</b> </p> <p>This is implemented as follows: </p> <codeblock id="GUID-9EE6666F-A4A7-5437-8AF1-CB0F8E2D6F0F" xml:space="preserve">void CCountServSession::CounterValue(const RMessage2&amp; aMessage)
       
   158     {
       
   159     TPckgBuf&lt;TInt&gt; p(iCount);
       
   160     aMessage.WriteL(0,p);
       
   161     }</codeblock> <p>It writes data back to a descriptor in the client address
       
   162 space. The corresponding client request is: </p> <codeblock id="GUID-A772B781-18E8-5109-BB6F-8871F829A8B5" xml:space="preserve">TInt RCountServSession::CounterValue()
       
   163     {
       
   164     TInt res=0;
       
   165     TckgBuf&lt;TInt&gt; pckg;
       
   166     
       
   167       // Note that TPckgBuf is of type TDes8
       
   168     TIpcArgs args(&amp;pckg);
       
   169     SendReceive(ECountServValue, args);
       
   170     
       
   171       // Extract the value returned from the server. 
       
   172     res = pckg();
       
   173     return res;
       
   174     }</codeblock> <p><b>Notes</b> </p> <ul>
       
   175 <li id="GUID-EC003B28-3695-5B19-8074-54DB06B720B8"><p>The <codeph>TInt</codeph> is
       
   176 packaged into a descriptor before being passed to the server. The packaging
       
   177 mechanism is known as package buffer. </p> </li>
       
   178 <li id="GUID-BB34EFC9-D238-509C-98C1-66BC64AA6EE2"><p>The write operation
       
   179 copies the descriptor, i.e. the package buffer containing the integer value,
       
   180 back to the descriptor in the client address space. Note that the zero specified
       
   181 in <codeph>aMessage.WriteL(0,p);</codeph> means that the argument referred
       
   182 to is the first in the list passed across from the client side via the <codeph>TIpcArgs</codeph> object. </p> </li>
       
   183 </ul> </section>
       
   184 </conbody></concept>