逐步实现TCP服务端Step03-12:改进

回忆一下字节流,code和消息之间的转换过程:

图中使用的函数名可能与代码中的不完全一样,这里的名字主要是描述当前在做的事情。

Message系列的类不会用在netio中,因为netio只负责通信,不考虑业务。后面的s需要把code解析成消息进行处理。

在s中又维护了一个叫做code_queue的code队列,维护这个队列是为了,把从c2s_code_queue中取code与对code进行处理的逻辑解耦。从c2s_code_queue中弹出一个code后,并不一定要立即处理它,应该先找个地方把它存起来。

DispatchMessage的语意是“派遣”消息,即根据消息ID和类型将消息分发给某个处理函数。要做到这一点,在Dispatch的时候,消息ID和类型必须是已知的。消息ID和类型存在于消息首部之中,因此,需要对首部进行Decode操作。

若在DispatchMessage内(由DecodeMessage完成)对消息首部解码,不符合Dispatch的语义,到了DispatchMessage这一步应该能直接使用消息首部信息。DispatchMessage不关注首部解码,就意味着它要从其它地方读取解码后的首部信息。需要一个队列专门存储code解码后的消息,即消息队列。

提前解码消息首部是必要的,而对消息体的解码应放到后面。因为,只有在实际处理业务时,才会关注消息体,提前解析没有意义。提前解码消息首部还可方便做一些校验工作,比如,通过查询消息的来源和目标实体来判定当前消息是否该由当前实体来处理。消息队列实际只存放各消息的首部信息即可,至于消息体,还是以code的形式存在于code队列中。同时,基于消息队列中的某个元素,必须能从code队列中检索出相应的code才行。

把从c2s_code_queue中弹出的code分解为消息头和消息体code的过程封装在ConvertClientCode2Message函数内。将消息头和消息体code分别push到队列中的过程封装为PostMessage函数。

修改后的流程:

把PopCodeFront、ConvertClientCode2Message、PostMessage这三步封装到GetClientMessages函数中。这三步是一个循环,取code->转换->存储消息,在一次GetClientMessages调用时,可以有多次循环。

类似地,一次DispatchMessages调用,其中的流程也可以有多次循环:

这次主要改动s.cc文件,GetClientMessages、PostMessage、DispatchMessages等函数的实现均在s.cc中。在能使用Message系列类的地方均进行了更新。不过,由于“消息队列”尚未实现,DispatchMessages函数无法完成。编译出来的s暂时不能工作,后面继续讨论消息队列的实现。

新增了requestecho.h、requestecho.cc和msgdefine.h文件,它们被放在message目录下。以后所有具体消息体类的定义都集中放在该目录下。

<==  index  ==>