简介
本文概述基于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数据 |
其余的没什么变动。
总结
本文介绍了服务器逻辑和网络层的设计,并且基于这个架构,完善了消息发送结构,下一篇带着大家设计逻辑类和逻辑队列。