一切像雾像雨又像风
作者: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_为例)
如上例所示,session管理类对消息的处理方式必须简单固定,方便可持续维护、扩充。二 Session的职责(1)数据结构:每一路连接的业务处理部分,首先有sessionid_标记session本身,其次包含业务处理需要的必须的数据部分,另外最重要的一个数据结构就是状态机了。(2)状态机。状态机标识session对象的状态,接收外部输入的事件,驱动状态机运行,并作出行为响应。详细见《技术系列之 状态机(一)》和《技术系列之 状态机(二)》,不多说了。(3)方法。主要分两类:on_msg和do_event。举例如下:
注意:1、所有有可能改变session内蕴状态的操作都必须纳入状态机的严格控制,不能存在不通过状态机即可改变session内蕴状态的操作入口。2、如果两个状态对同样的事件做出同样的反应,并且都迁移到相同的状态,那么这两个是同一个状态。3、尽可能减少状态的个数。如果两个状态具有严格的时序关系,处理的事件不同并且有严格的时序关系,那么考虑合并这两个状态,防止状态机膨胀。
三 总结:理解业务部分,先区分消息(Msg)和事件(Event)。1、消息(Msg):是指线程之间传递的数据结构,即被投递到线程消息队列中的数据结构。SessionManager主要职责是接收消息,通过消息映射,找到处理该消息的函数,该函数根据消息中携带的sessionid,找到session对象,调用该session的消息处理函数继续后续的处理。2、事件(Event):是指被session对象中的状态机处理的数据结构。该数据结构,在session的消息处理函数中通过消息的内容拼凑,之后交给状态机对象处理,状态机对象根据事件类型,通过事件映射,找到处理该事件的函数,继续该事件的处理。3、代码流程:一般情况下(逻辑控制部分)其它线程不能直接调用session对象,正确的调用方式是发消息SessionManager,SessionManager根据消息找到session对象再进行后续处理。4、代码要写的足够呆板。 写出好的系统关键在于对业务的理解,不在于对代码技巧的玩弄。
Powered by: C++博客 Copyright © cppexplore