18款禁用黄app入口直接看长沙网站seo优化
前置
跨平台C++包管理利器vcpkg完全指南
一、为什么需要自定义协议?
1. 常见问题
- 粘包/半包:TCP是流式协议,数据可能被拆分成多个包或合并。
- 数据校验:传输过程中可能发生比特错误或篡改。
- 跨平台兼容性:不同系统对数据类型(如整型字节序)的处理不同。
2. 解决方案
- 定长消息:每个消息固定长度(简单但不够灵活)。
- 分隔符:用特殊字符(如\r\n)分割消息(需转义处理)。
- 长度前缀:在消息头声明数据长度(推荐方案)。
二、设计二进制协议(自定义)
1. 协议格式示例
| 魔数(4B) | 版本(1B) | 类型(1B) | 长度(4B) | 数据(N B) | CRC32(4B) |
字段说明:
- 魔数:固定值(如0xDEADBEEF),用于识别协议起始。
- 版本:协议版本号,支持向后兼容。
- 类型:消息类型(如请求、响应、心跳)。
- 长度:数据部分的字节数。
- 数据:有效载荷(如序列化的JSON或二进制数据)。
- CRC32:校验和,验证数据完整性。
2. C++示例
#include <cstdint>
#include <vector>
#include <cstring>
#include <zlib.h>
#include <iostream>
#include <stdexcept>
#include <winsock2.h>
#pragma comment(lib, "ws2_32.lib")// 平台字节序处理(示例为小端模式)
#if defined(_MSC_VER)
# define htonl(x) _byteswap_ulong(x)
#elif defined(__GNUC__)
# define htonl(x) __builtin_bswap32(x)
#endif// 严格内存对齐的协议头
#pragma pack(push, 1)
struct PacketHeader {uint32_t magic; // 固定魔数 0xDEADBEEFuint8_t version; // 协议版本uint8_t type; // 数据类型标识uint32_t length; // 载荷长度(网络字节序)PacketHeader(uint8_t t = 1, uint32_t len = 0): magic(htonl(0xDEADBEEF)), // 存储为网络字节序version(1),type(t),length(htonl(len)) {}
};
#pragma pack(pop)// 编码函数:生成带校验的数据包
std::vector<uint8_t> EncodePacket(uint8_t type, const std::vector<uint8_t>& payload) {if (payload.size() > 0xFFFFFFFF) {throw std::invalid_argument("Payload too large");}// 构造协议头PacketHeader header(type, static_cast<uint32_t>(payload.size()));// 计算CRC32(头+载荷)std::vector<uint8_t> tempBuffer;tempBuffer.reserve(sizeof(header) + payload.size());tempBuffer.insert(tempBuffer.end(),reinterpret_cast<uint8_t*>(&header),reinterpret_cast<uint8_t*>(&header) + sizeof(header));tempBuffer.insert(tempBuffer.end(), payload.begin(), payload.end());uLong crc = crc32(0L, Z_NULL, 0);crc = crc32(crc, tempBuffer.data(), tempBuffer.size());uint32_t netCrc = htonl(crc); // CRC也转为网络字节序// 组装完整包std::vector<uint8_t> packet;packet.insert(packet.end(), tempBuffer.begin(), tempBuffer.end());packet.insert(packet.end(),reinterpret_cast<uint8_t*>(&netCrc),reinterpret_cast<uint8_t*>(&netCrc) + sizeof(netCrc));return packet;
}// 解码函数:验证并提取数据
bool DecodePacket(const std::vector<uint8_t>& packet,uint8_t& type,std::vector<uint8_t>& payload) {// 基础长度检查const size_t minSize = sizeof(PacketHeader) + sizeof(uint32_t);if (packet.size() < minSize) return false;// 解析协议头PacketHeader header;memcpy(&header, packet.data(), sizeof(header));header.magic = ntohl(header.magic); // 转换为主机字节序header.length = ntohl(header.length);// 魔数和版本校验if (header.magic != 0xDEADBEEF || header.version != 1) {return false;}// 载荷长度校验const size_t expectedSize = sizeof(header) + header.length + sizeof(uint32_t);if (packet.size() != expectedSize) {return false;}// 提取CRC并转换字节序