CppExplore

一切像雾像雨又像风

  C++博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  29 随笔 :: 0 文章 :: 280 评论 :: 0 Trackbacks

作者:CppExplore 网址:http://www.cppblog.com/CppExplore/
网络请求包经过网络层(技术系列综述(一))被解析翻译成程序自定义的消息,之后被投递到业务线程的线程消息队列(技术系列综述(二))中。业务线程在队列的另一端取出消息,开始处理,这是本章要介绍的部分。业务处理部分:主要有会话类(Session)和会话管理类(SessionManager,常见该类为单例)。先给出类图,后文详细介绍:

一 SessionManager的职责
(1)继承IMsgThread(技术系列综述(二)),调用该类的start方法,启动业务线程
(2)提供on_.../do_...方法技术系列综述(二)),供其它线程向业务线程投递消息,以及消息在业务线程的处理入口。
(3)主要的私有属性是session类的容器对象。容器类的选型的依据,首先是查询性能,之后是插入删除的性能。
array:数组下标为session对象的seesionid_(此处sessionid,不要理解为常见协议中的session字段,可以理解为session对象的索引)。可以做到插入删除(参考内存管理chunk分配算法)查询都在o(1)完成,缺点不能动态增大。同样可以参考定长内存池的分配算法,动态申请255个array为一个chunk,所有chunk使用vector管理,各chunk中array编号递增255,同样可以达到增删查o(1)的效率。
缺点:(1)sessionid_重复使用,加上消息经过消息队列形成的处理延迟,可能造成下一个session对象处理上一个同样sessionid的session对象遗留下来的消息,实际使用中每个session对象有自己的状态机,这种残留的消息危害并不大。(2)需要自己实现,对比map的o(logn),这点细微的性能提升无任何意义(也就是减少了几次整型之间的对比)。相比不需要自己额外实现的普通数组还算有点实用价值。
vector:如果被插入的session的sessionid是递增的,查询可以做到折半查找logn的性能,但随机删除造成的内存移动是o(n),无法接受。
map:以红黑树为基础实现。增删查找的性能都可以平稳的保持在o(logn),sessionid_为整型或者其operater<实现简单的时候是最常用的容器。
hash_map:哈希表,使用大量内存尽量使数据均匀分布,查询性能分hashcode的计算(hash函数)和查找部分,hash函数一般为所有有效信息的移位计算(经典的是字符串的33算法)叠加,查找部分最理想的是0(1),最差是0(n),取决于hash函数计算结果碰撞的几率。当sessionid_为字符串或者其operater<实现复杂的时候常用。
(4)该类处理消息的方式举例如下:(容器以map<int,session *> mapSessions_为例)

void do_msg_type_1_(MsgData &msg)
{
  
int id=msg.sessionid;
  
if(mapSessions_.find(id)!=mapSessions_.end())
  
{
    session 
*pSession=mapSessions_[id];
    pSession
->on_msg_1(msg);
  }

  
else
  
{
    write_warning_log;
  }

}


如上例所示,session管理类对消息的处理方式必须简单固定,方便可持续维护、扩充。
二 Session的职责
(1)数据结构:每一路连接的业务处理部分,首先有sessionid_标记session本身,其次包含业务处理需要的必须的数据部分,另外最重要的一个数据结构就是状态机了。
(2)状态机。状态机标识session对象的状态,接收外部输入的事件,驱动状态机运行,并作出行为响应。详细见技术系列之 状态机(一)技术系列之 状态机(二),不多说了。
(3)方法。主要分两类:on_msg和do_event。举例如下:

void on_msg(MsgData &msg)
{
    EventData 
event;
    
event.detail=msg.detail;//todo
    fsm.do_event(event);
}

void do_event..(EventData &event)
{
    
//change session's data or send msg to other thread or response request or others.. 
}

注意:
1、所有有可能改变session内蕴状态的操作都必须纳入状态机的严格控制,不能存在不通过状态机即可改变session内蕴状态的操作入口。
2、如果两个状态对同样的事件做出同样的反应,并且都迁移到相同的状态,那么这两个是同一个状态。
3、尽可能减少状态的个数。如果两个状态具有严格的时序关系,处理的事件不同并且有严格的时序关系,那么考虑合并这两个状态,防止状态机膨胀。

三 总结:
理解业务部分,先区分消息(Msg)和事件(Event)。
1、消息(Msg):是指线程之间传递的数据结构,即被投递到线程消息队列中的数据结构。SessionManager主要职责是接收消息,通过消息映射,找到处理该消息的函数,该函数根据消息中携带的sessionid,找到session对象,调用该session的消息处理函数继续后续的处理。
2、事件(Event):是指被session对象中的状态机处理的数据结构。该数据结构,在session的消息处理函数中通过消息的内容拼凑,之后交给状态机对象处理,状态机对象根据事件类型,通过事件映射,找到处理该事件的函数,继续该事件的处理。
3、代码流程:一般情况下(逻辑控制部分)其它线程不能直接调用session对象,正确的调用方式是发消息SessionManager,SessionManager根据消息找到session对象再进行后续处理。
4、代码要写的足够呆板。
   写出好的系统关键在于对业务的理解,不在于对代码技巧的玩弄。

 

posted on 2008-12-22 14:27 cppexplore 阅读(4543) 评论(6)  编辑 收藏 引用

评论

# re: 【原创】技术系列综述(三) 2008-12-23 10:57 kacy16
非常谢谢cppexplore无私的把自己实际经验无私的分享,感觉这些思路(经验)都非常的实用,考虑到了实际情况的扩展性,效率等各方面,不像一些书本的资料夸夸其谈,提供的思路要不全是抽象的理论,要不就是一整个花架子(就像小孩过家家的玩意).非常谢谢!  回复  更多评论
  

# re: 【原创】技术系列综述(三) [未登录] 2008-12-23 21:19 cppexplore
@kacy16
:)  回复  更多评论
  

# re: 【原创】技术系列综述(三) 2009-04-01 11:30 中国兄弟连
给你踩踩哈  回复  更多评论
  

# re: 【原创】服务器技术系列综述(三) 2009-12-26 05:38 浩毛
拒绝线程,珍爱生命  回复  更多评论
  

# re: 【原创】服务器技术系列综述(三) 2010-04-13 16:05 zhaojx
大牛,我刚毕业一年,工作中的很多内容在你的文章里都有,你的文章真的是总结到我的心坎里了,好多东西都是这么熟悉,但是就是因为自己没有总结,看了你的文章,真的是颇有收获,希望你能继续写下去  回复  更多评论
  

# re: 【原创】服务器技术系列综述(三) [未登录] 2010-04-13 16:48 cppexplore
@zhaojx
很高兴你能喜欢我写的内容, :)   回复  更多评论
  


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理