一篇较简单的介绍CS模式的文章

Symbian中的Client/Server机制

Server和Client一般在不同的进程中运行,因此它们之间的通讯需要使用内核提供的某种IPC机制来进行通讯。Symbian提供一些封装好了的RSessionBase/CServer/CSession类供Client来建立和Server之间的连接,C/S之间通过消息(RMessage类)来进行通信,这样将内核的IPC实现细节隐藏在C++的函数调用中。

可以将Symbian中的C/S结构类似到一个基于TCP的Socket实现中。在一个典型的TCP Socket连接中,大概有如下的步骤:

1.  Server启动,阻塞在Accept中等待客户请求

2.  Client创建一个Socket,调用Connect尝试进行连接

3.  Server从Accept返回,创建一个新的Socket和该Client进行通信

Symbian的C/S结构为:

1.  Client创建一个RSessionBase,调用Connect方法连接Server

2.  CServer当时阻塞在NewSession中,收到客户连接请求后,创建一个CSession该Client进行通信

3.  然后Client通过RSessionBase::SendReceive发送请求,Server端的CSession收到该请求并执行之

因此,RSessionBase类似于TCP Socket中的Client端的套接字,CServer就是Server端那个Listen的套接字,CSession就是Server端用来和client通信的套接字。当然它们实际上有太多的不同。

稍微具体一点的基本流程是

首先,Server开发者一般会提供给Client一个RSessionBase的派生类,例如我们常见的RFs。在这个RSessionBase的派生类中,封装了一些函数,例如如何建立一个到Server的连接(按照惯例,该函数命名为Connect),如何将request进行封装等。

ClientServer之间的典型通讯步骤:

1.  Client调用一个RSessionBase派生类的Connect函数,例如 RMyServerSession::Connect

2.  该函数内部实现将寻找当前系统运行的Server(通过TFindServer),如果没有发现该Server运行,则;

3.  启动该Server(通过RThread::Create函数在另一个线程中启动,或者通过RProcess::Create函数在一个独立的进程中启动该Server,后面这种比较常见)。

Server被启动后,Server内部的实现大概如下:

在Server线程中,首先安装一个CActiveScheduler,然后创建一个具体的CServer对象,CServer本身继承自CActive,这样就使得Server可以被CActiveScheduler调度。然后启动该Server(调用CServer::StartL,大概CServer的内部实现是调用基类CActive::SetActive,表明自己发出了一个请求,希望该请求完成时被调度,对于CServer,它发出的请求就是希望收到Client的连接),然后进入wait loop(调用CActiveScheduler::Start函数)。当有客户通过CreateSession发送连接请求时,Scheduler将调用CServer::NewSessionL函数。

 

4.  client调用RSessionBase::CreateSession函数建立一个到Server的连接(通过Server的名字)。(估计内核根据Server名字,找到对应该名字的线程RThread,然后就可以建立一个通道,估计RSessionBase中的iHandler成员变量用来代表这个连接通道,同时估计Server端的CSession中的RThread iClient成员变量也被Server用来表示这个连接通道)。

5.  通过某种IPC机制,我们的CServer派生类的NewSesssion函数被调用,(即Client端的CreateSession会对应到Server端的NewSession函数中,当然这是由内核完成的。于是我们创建一个CSession派生类来和Client进行联系,该派生类继承来的CSession对象中包含了一个表示Client所在线程的RThread对象iClient。

6.  Client通过RSessionBase的SendReceive发送一个请求并期待获得返回信息。系统内部会将之转换成一个RMessage并调用Server端CSession的一个虚拟函数。

7.  Server端代表该client连接的CSession对象(在第5步时被创建)的ServiceL(const RMessage& aMessage)虚拟函数被调用,其中的aMessage对象包含了Client的请求信息。

8.  Server根据该aMessage的内容,调用合适的处理函数。

9.  Server调用Message().Complete()通知Client该命令处理完毕。 (任何时候都可以调用Message()来获得当前Session中的消息)。内部实现可能是给Client所在的Thread中的信号量加一(CSession中有个成员变量RThread iClient,而RThread中有一个函数可以用来给于该线程关联的信号量加一)。

 

大致就是如此。

一个简单的C/S端的对应关系如下:

Client Server

RSessionBase::Connect <---> Launch server.exe

RSessionBase::CreateSession <---> CServer::NewSession

RSessionBase::SendReceive <---> CSession::ServiceL

posted @ 2010-04-11 14:51  秋天的风  阅读(386)  评论(0编辑  收藏  举报