目录
需求确认
回顾 MQ 的交互模型:

其中生产者和消费者都是客户端, 它们都需要通过网络和 Broker Server 进行通信。具体通信的过程我们使用 Muduo 库来实现, 使用 TCP 作为通信的底层协议, 同时在这个基础上自定义应用层协议, 完成客户端对服务器功能的远端调用。 我们要实现的远端调用接口包括:
- 创建 channel;
- 关闭 channel;
- 创建 exchange;
- 删除 exchange;
- 创建 queue;
- 删除 queue;
- 创建 binding;
- 删除 binding;
- 发送 message;
- 订阅 message;
- 发送 ack;
- 返回 message (服务器 -> 客户端)。
设计应用层协议
使用二进制的方式设计应用层协议。
因为 MQMessage 的消息体是使用 Protobuf 进行序列化的,本身是按照二进制存储的,所以不太适合用 json 等文本格式来定义协议。
下面我们设计一下应用层协议:请求/响应报文设计

- len:4 个字节, 表示整个报文的长度。
- nameLen: 4 个字节, 表示 typeName 数组的长度。
- typeName:是个字节数组, 占 nameLen 个字节, 表示请求/响应报文的类型名,作用是分发不同消息到对应的远端接口调用中。
- protobufData:是个字节数组, 占 len - nameLen - 8 个字节, 表示请求/响应参数数据通过 protobuf 序列化之后的二进制。
- checkSum:4 个字节, 表示整个消息的校验和, 作用是为了校验请求/响应报文的完整性。
定义请求/响应参数
因为这里的参数需要进行网络传输以及序列化, 所以我们需要将参数定义在 pb 文件中。
syntax = "proto3";
package jiuqi;
import "msg.proto";
// 信道的打开与关闭
message openChannelRequest
{
string rid = 1; // 请求id
string cid = 2; // 信道id
};
message closeChannelRequest
{
string rid = 1;
string cid = 2;
};
// 交换机的声明与删除
message declareExchangeRequest
{
string rid = 1;
string cid = 2;
string ename = 3;
ExchangeType etype = 4;
bool durable = 5;
bool auto_delete = 6;
map<string, string> args = 7;
};
message deleteExchangeRequest
{
string rid = 1;
string cid = 2;
string ename = 3;
};
// 队列的声明与删除
message declareQueueRequest
{
string rid = 1;
string cid = 2;
string qname = 3;
bool exclusive = 4;
bool durable = 5;
bool auto_delete = 6;
map<string, string> args = 7;
};
message deleteQueueRequest
{
string rid = 1;
string cid = 2;
string qname = 3;
};
// 队列的绑定与解除绑定
message queueBindRequest
{
string rid = 1;
string cid = 2;
string ename = 3;
string qname = 4;
string bindingkey = 5;
};
message queueUnbindRequest
{
string rid = 1;
string cid = 2;
string ename = 3;
string qname = 4;
};
// 消息的发布
message basicPublishRequest
{
string rid = 1;
string cid = 2;
string ename = 3;
string body = 4;
BasicProperties properties = 5;
};
// 消息的确认
message basicAckRequest
{
string rid = 1;
string cid = 2;
string qname = 3;
string mid = 4;
};
// 队列的订阅
message basicConsumeRequest
{
string rid = 1;
string cid = 2;
string ctag = 3; // 消费者标识
string qname = 4;
bool auto_ack = 5;
};
// 订阅的取消
message basicCancelRequest
{
string rid = 1;
string cid = 2;
string ctag = 3;
string qname = 4;
};
// 消息的推送
message basicConsumeResponse
{
string cid = 1;
string ctag = 2;
string body = 3;
BasicProperties properties = 4;
};
// 通用响应
message basicCommonResponse
{
string rid = 1;
string cid = 2;
bool ok = 3;
};