// 协议都是网络字节序
/**
请求格式
1 1 2 4 4 4 Len
+---+---+-------+---------------+---------------+---------------+------------------+
| Q | V | VER | Len | SEQ | CMD | Msg |
+---+---+-------+---------------+---------------+---------------+------------------+
*/
typedef struct {
uint8_t QV[2]; // 请求标记
uint16_t ver; // 协议版本
uint32_t len; // msg长度 + sizeof(uint32_t), 主机序
uint32_t seq; // seq标记, 请求和响应会一致
uint32_t cmd; // 请求的命令
uint32_t msglen; // msg长度
uint8_t msg[0]; // 请求的消息
void SetLen(int l) { len = htonl(l + sizeof(uint32_t)); msglen = htonl(l); };
void SetSeq(int s) { seq = htonl(s); };
void SetCmd(int c) { cmd = htonl(c); };
int GetSeq() { return ntohl(seq); };
int GetCmd() { return ntohl(cmd); };
int GetLen() { return ntohl(len) - sizeof(uint32_t); };
int GetPkgLen() { return ntohl(msglen); };
} __attribute__((packed)) ProtoReq;
/**
响应格式
1 1 2 4 4 4 4 8 Len
+---+---+-------+---------+---------+---------+--------+---------+-----------------+
| Q | A | VER | Len | SEQ | CMD | Errno | 保留 | Msg |
+---+---+-------+---------+---------+---------+--------+---------+-----------------+
*/
typedef struct {
uint8_t QA[2]; // 响应标记
uint16_t ver; // 协议版本
uint32_t len; // 返回数据的长度; msglen + 4
uint32_t seq; // 请求时传入的seq
uint32_t cmd; // 请求时传入的cmd
int32_t err; // 设置的返回值;
uint64_t mark; // 保留字段
uint32_t msglen; // 消息长度,
uint8_t msg[0]; // 返回的消息体
void Build(const ProtoReq &req)
{
QA[0] = 'Q', QA[1] = 'A';
ver = req.ver;
seq = req.seq;
cmd = req.cmd;
err = 0;
mark = 0;
}
void SetLen(int l) { len = htonl(l + sizeof(uint32_t)); msglen = htonl(l); };
int GetLen() { return ntohl(len) - sizeof(uint32_t); };
void SetErr(int e) { err = htonl(e); };
int GetErr() { return ntohl(err); };
int GetSeq() { return ntohl(seq); };
int GetPkgLen() { return ntohl(msglen); };
} __attribute__((packed)) ProtoRsp;
// 验证请求正确性
// > 0 返回正数表示数据已经接收完整且该值表示数据包的长度,
// = 0 表示数据包还未接收完整,
// < 0 表示出错
static inline int CheckProtoReq(const char *data, size_t len)
{
ProtoReq *req = (ProtoReq *)data;
if (len < sizeof(ProtoReq))
return 0;
if (req->QV[0] != 'Q' || req->QV[1] != 'V')
return -1;
uint32_t total = req->GetLen() + sizeof(ProtoReq);
return len < total ? 0 : total;
}
static inline int CheckProtoRsp(const char *data, size_t len)
{
ProtoRsp *req = (ProtoRsp *)data;
if (len < sizeof(ProtoRsp))
return 0;
if (req->QA[0] != 'Q' || req->QA[1] != 'A')
return -1;
uint32_t total = req->GetLen() + sizeof(ProtoRsp);
return len < total ? 0 : total;
}