简介
本文概述基于boost::asio实现的服务器逻辑层结构,并且完善之前设计的消息结构。因为为了简化粘包处理,我们简化了发送数据的结构,这次我们给出完整的消息设计,以及服务器架构设计。
服务器架构设计
之前我们设计了Session(会话层),并且给大家讲述了Asio底层的通信过程,如下图

我们接下来要设计的服务器结构是这样的

消息头完善
我们之前的消息头仅包含数据域的长度,但是要进行逻辑处理,就需要传递一个id字段表示要处理的消息id,当然可以不在包头传id字段,将id序列化到消息体也是可以的,但是我们为了便于处理也便于回调逻辑层对应的函数,最好是将id写入包头。
之前我们设计的消息结构是这样的

现在将其完善为如下的样子

为了减少耦合和歧义,我们重新设计消息节点。MsgNode表示消息节点的基类,头部的消息用这个结构存储。RecvNode表示接收消息的节点。SendNode表示发送消息的节点。
我们将上述结构定义在MsgNode.h中
1  | class MsgNode  | 
实现如下
1  | 
  | 
SendNode发送节点构造时,先将id转为网络字节序,然后写入_data数据域。
然后将要发送数据的长度转为大端字节序,写入_data数据域,注意要偏移HEAD_ID_LEN长度。
最后将要发送的数据msg写入_data数据域,注意要偏移HEAD_ID_LEN+HEAD_DATA_LEN
Session类改写
因为消息结构改变了,所以我们接收和发送数据的逻辑要做对应的修改,我们先修改Session类中收发消息结构如下
1  | std::queue<shared_ptr<MsgNode> > _send_que;  | 
因为头部数据只为4字节,所以我们在Session的构造函数中创建头部节点时选择HEAD_TOTAL_LEN(4字节)大小。
1  | CSession::CSession(boost::asio::io_context& io_context, CServer* server):  | 
发送时我们构造发送节点,放到队列中即可
1  | void CSession::Send(char* msg, short max_length, short msgid) {  | 
当然我们也实现了一个重载版本
1  | void CSession::Send(std::string msg, short msgid) {  | 
在接收数据时我们解析头部也要解析id字段
1  | void CSession::HandleRead(const boost::system::error_code& error, size_t bytes_transferred, std::shared_ptr<CSession> shared_self){  | 
先解析头部id,再解析长度,然后根据id和长度构造消息节点,copy剩下的消息体, 把上面代码中处理消息头的逻辑截取如下
1  | //获取头部MSGID数据  | 
其余的没什么变动。
总结
本文介绍了服务器逻辑和网络层的设计,并且基于这个架构,完善了消息发送结构,下一篇带着大家设计逻辑类和逻辑队列。