文章目录
仓库路径
项目地址:license-server
0. 工程结构
项目包括以下主要模块和组件:
loghelper
:简单的日志组件json_message_processor
:处理JSON消息的编码和解码daemon
:守护进程相关功能conf
:项目和消息的配置文件license-client
:以动态链接库方式提供的license客户端license-server
:基于boost.asio实现的license服务端,内部集成看门狗服务(相关代码已移除)
1. 消息格式
消息格式说明如下表所示:
消息 | 长度(BYTES) | 结构 | 描述 |
---|---|---|---|
Header | 4 | SyncBytes | 同步字节,固定格式0x09, 0x6f, 0x01, 0x01,表示设备间交互 |
Header | 4 | FullMessageLength | 总消息长度,包括SyncBytes和FullMessageLength |
Header | 4 | MessageSeq | 消息序列号,递增 |
Header | 4 | MessageType | 消息类型(消息号),如登录消息或发送消息 |
Header | 4 | StringBodyLength | 消息字符流长度,可以是JSON流、XML流或普通字符流 |
Header | 12 | Reserved | 保留字段,共12字节 |
Body | StringBodyLength | StringBody | 消息体,可以是JSON、XML或普通字符串数据 |
Body | FullMessageLength - 32 - StringBodyLength | BinaryData | 二进制数据,长度由FullMessageLength - 32 - StringBodyLength计算得出 |
2. license控制
license-server
默认配置maxLicenseNum,限制最大客户端连接数。- 每次客户端认证,maxLicenseNum减1,直至为0。
- 客户端断开连接或停止服务,maxLicenseNum加1。
3. 网络库
- 使用boost.asio实现的异步网络库。
license-client
已隐藏boost依赖,供调用方使用。- 参考boost库示例实现,如
asio/example/cpp03/timeouts/server.cpp
和asio/example/cpp03/chat/chat_client.cpp
。
4. License-Client
- C++客户端模块以动态链接库方式提供。
- 提供以下接口:
void start(ClientConfig& cfg, MessageType_t& messageTypes, std::function<void(int)> cb); void stop(); void sendHeartbeatReq(); void sendLoginReq(); void sendLogoutReq(); void sendGetDogStatusReq();
5. License-Server
5.1 各模块关系
- 设计说明:
- 使用PIMPL方式隐藏实现细节,减少对外接口暴露。
- 每个
tcpclient
对应一个TcpServerSession
对象,由SessionManager
统一管理。 MessageHandler
处理具体业务逻辑,JsonMessageProcessor
专门处理JSON消息的编码和解码。main
函数负责加载配置和消息映射表,可以独立为一个模块。
5.2 消息触发流程
TcpClientImpl
异步读取消息流程:- 当读取到32字节的消息头时,触发
handlerReaderHeader
,预处理完成后分发给注册的MessageHandler::onReadHeader
处理。 - 当读取到完整的
TcpMessage
后,触发handleReadBody
,预处理完成后分发给onReadBody
处理。
- 当读取到32字节的消息头时,触发
5.3 消息处理流程
- 处理LoginReq消息流程:
- 首先读取消息头,检查是否正确,继续执行。
- 然后读取消息体,在
readBody
中分发消息到具体处理函数,在onLoginReq
中调用dogService.getCurrentStatus
。 - 最后,组装并通过
TcpServerSession
的write
方法发送LoginRsp消息。
6. 心跳和保活
- 双向心跳设计:
- 客户端和服务端各自实现心跳机制,保证license及时释放。
- 客户端有连接断开重连机制,可配置开启。
7. 守护进程设计
- 设计要点:
- 守护进程和工作进程需位于同一目录。
- 仅支持单个工作进程,重复启动时先杀掉同名进程。
- Linux平台需处理僵尸进程问题。