Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1538526
  • 博文数量: 237
  • 博客积分: 5139
  • 博客等级: 大校
  • 技术积分: 2751
  • 用 户 组: 普通用户
  • 注册时间: 2008-11-18 14:48
文章分类

全部博文(237)

文章存档

2016年(1)

2012年(4)

2011年(120)

2010年(36)

2009年(64)

2008年(12)

分类: C/C++

2009-11-25 10:26:53

Symbian CS结构主要的类关系如下:

其中重要的几个函数:

一般在client端会有connect(), 这个函数是自己写的,名字随便,但是功能是建立server进程(如果有的话就通过名字find),然后调用RSessionBase的 CreateSession()函数,这里面建立了一个session的内核对象。个人感觉凡事R打头的类在symbian里都封装了相应的系统调用。通过这些个操作进入内核。

要注意的是,在建立server进程的时候,一般有一个wait来等server那边start起来,再signal回来。当这个wait开启,server那边进线程函数,e32main里面会自构造一个cserver2的派生类(注意cserver2是一个活动对象)。

这么看server线程里面实际就是一个活动对象套在schedule里面,schedule在不断的循环看看是否有消息从client那边过来。

在构造cserver2的派生类对象的时候,会调用cserver2的startL函数,这个函数很关键。

CServer2::StartL()

{

CreateKernelServerObject; // via system call

default add itself into schedule loop//because in symbian example "acyncclientserver",i can not find schedule::add 

//(CServer2),so add AO must be implemented by server2 itself.

SetActive();

set kernel object buff for server.

}

 再看一下CServer2的结构

class CServer2::CAtive

{

data:

RMessage2 iMessage;

RServer2 iServer;

}

please note that creating server kernel object use RServer handler which is similar to RSessionBase on client side.

在StartL的最后会在server内核对象里面 把server usermode 的数据结构RMessage2的引用付给server 内核数据结构。这样有数据从client那边过来的时候,内核可以通过先accept 再delivery把数据从client那边拿到server的内核空间,然后再通过startl建立的usermode和kernelmode的关系付 给rmessage2.

startl运行完成后,server的内核对象DServer已经建立了,并且DServer buff已经包含了RMessage2的引用。这就是server准备就绪了。

那么下边的工作就是client那边createsession。

CreateSession()

{

CreateSessionKernelObject; //DSession

Add DSession obejct to DServer // via the first param ServerName to loop find in all servers list.

Version match and send AO Status.

}

please note that the first communication between server and client happened at the stage "version match".

版本匹配是第一次通信的发生地,第一次的send recieve就是在这里发生的。这个里面在cserver2收到version之后会根据version建立server端session的内核对象, 也是DSession,通过一个虚函数NewSessionL建立的,server usermode的代码必须有一个派生于CSession2的类来实现。这样就真正建立了,一个DServer控制两个DSession。每个 RMessage2 对象里面关联了一个CSession2的指针,这样的话虽然server的buf就一块。但是每个数据都能找到对应的session。RMessage2 有很多份。

后面讲述client的server通信的细节:

client 通过RSessionBase的sendrecieve函数来和server通信。

要注意通信client使用的参数TIpcArgs,实际是个指针数组,用模板构造函数将自己构造成存放最多4个地址的数据结构。

如果这么写 TIpcArgs args( &aPtr );  那么args的值就是tptr对象的首地址,传到server那边的rmessage2的也是这个地址。

这个数据结构在内核中也有一个结构与之对应,但是内核中的结构里面保留了更多关于client的信息,比如status和 sessionlink。,这些数据最终会在server accept的时候付给server的数据buf,并且reqeustcomplete服务器线程,至此client发数据结束。

在RequestComplte里面给信号量的时候会强制将server的status制成KErrNone,这点是和client那边的区别。

server在收到信号量之后会通过callback的形式将messagedata的ptr付给messageptr。messageptr最终存放的就是RMessage2的引用。至此数据以传送给CServer2。

此时信号量有了,status是kErrNone了,CServer被激活进入runl处理数据,处理完通过Complete写回client,这会把client的status强制弄成KErrNone,这就是前面讲到的不一样的地方,server这边置client status的方法在客户代码里面,而client置server status的代码在内核。

complete将RMessgae2的数据通过sessionlink找到原来的那个client session的messagedata地址,在返回去。 同样里面会给client thread 信号量,至此一次数据传递结束。

这里在写程序的时候最好要保证你用server WriteL的时候,你client的那边的数据载体的生命周期够长,否则就会一直WriteL的leave, bad desciriptor错误 -38. 建议在client那边弄个成员变量Tbuf什么的,直接把TBuf package and send 过去。

Notes: 在client createprocess的时候, 可以不用RSamepore.wait 来等待服务器那边 RSemapore.signal, symbian 提供了现在client那边把你的服务器这样

 RProcess server;

server.Logon();

User::WaitForRequest();

然后等server初始化好了在server那边 用RProcess::::Rendezvous() 去request 所有logon的线程。

从CS架构的示例代码中看到两种方式.

1. 信号量。来自S60Ex/ClientServerSync
//=================client process========
    RSemaphore semaphore;
    result = semaphore.CreateGlobal( KTimeServerSemaphoreName, 0 );
    if ( result != KErrNone )
        {
        return result;
        }

    result = CreateServerProcess();
    if ( result != KErrNone )
        {
        return result;
        }

    semaphore.Wait();
    semaphore.Close();
//===========server process========
    RSemaphore semaphore;
    User::LeaveIfError( semaphore.OpenGlobal( KTimeServerSemaphoreName ) );

    // Semaphore opened ok
    semaphore.Signal();
    semaphore.Close();


2. RProcess::Rendezvous 这个更简单
//============client process================
    TRequestStatus stat;
    server.Rendezvous(stat);
    if(stat != KRequestPending)
    {
        server.Kill(0);        // abort startup
    }
    else
    {
        server.Resume();    // logon OK - start the server
    }

    User::WaitForRequest(stat);        // wait for start or death
//===========server process========
    RProcess::Rendezvous(KErrNone);
阅读(1045) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~