文章目录
- 🍃前言
- 🎍明确需求
- 🍀设计应用层协议
- 🎄定义 Request / Response
- 🌴定义参数父类与返回值父类
- 🌲定义其他参数类
- 🌳定义其他返回类
- ⭕总结
🍃前言
本次开发任务
- 设计网络通信协议
用于客户端和服务器之间的通信
🎍明确需求
我们先来看一下我们最初的客户端与服务器的交互模型
我们可以看到,生产者和消费者都是客户端,都需要通过网络和Broker Server 进行通信。
此处我们使用 TCP 协议,来作为通信的底层协议。同时在这个基础上自定义应用层协议,完成客户端对服务器这边功能的远程调用。
要调用的功能有:
- 创建 channel
- 关闭 channel
- 创建 exchange
- 删除 exchange
- 创建 queue
- 删除 queue
- 创建 binding
- 删除 binding
- 发送 message
- 订阅 message
- 发送 ack
- 返回 message (服务器 -> 客户端)
🍀设计应用层协议
我们这里使⽤⼆进制的方式设定协议
请求与相应报文格式如下:
- 请求
- 响应
其中 type 表⽰请求响应不同的功能,取值如下:
- 0x1 创建 channel
- 0x2 关闭 channel
- 0x3 创建 exchange
- 0x4 销毁 exchange
- 0x5 创建 queue
- 0x6 销毁 queue
- 0x7 创建 binding
- 0x8 销毁 binding
- 0x9 发送 message
- 0xa 订阅 message
- 0xb 返回 ack
- 0xc 服务器给客⼾端推送的消息。(被订阅的消息)响应独有的。
其中 payload 部分, 会根据不同的 type, 存在不同的格式。
对于请求来说, payload 表示这次方法调用的各种参数信息
对于响应来说, payload 表示这次方法调用的返回值
🎄定义 Request / Response
Request 类实现如下:
ublic class Request {
private int type;
private int length;
private byte[] payload;
// 省略 getter setter
}
Response 类实现如下:
public class Response {
private int type;
private int length;
private byte[] payload;
// 省略 getter setter
}
关于 payload里面的数据,我们另外用别的类进行表示。
🌴定义参数父类与返回值父类
构造⼀个类表示方法的参数,作为 Request 的 payload
不同的方法中,参数形态各异,但是有些信息是通用的,使用⼀个⽗类表示出来。具体每个⽅法的参数再通过继承的方式体现.
参数父类实现如下:
public class BaseArguments implements Serializable {
// 表⽰⼀次请求/响应的唯⼀ id. ⽤来把响应和请求对上.
protected String rid;
protected String channelId;
// 省略 getter setter
}
此处的 rid 和 channelId 都是基于 UUID 来生成的, rid 用来标识⼀个请求-响应。这⼀点在请求响应比较多的时候非常重要.
返回值父类和参数同理,也需要构造⼀个类表示返回值,作为Response 的 payload
代码实现如下:
public class BaseReturns implements Serializable {
// 表⽰⼀次请求/响应的唯⼀ id. ⽤来把响应和请求对上.
protected String rid;
protected String channelId;
protected boolean ok;
// 省略 getter setter
}
🌲定义其他参数类
针对每个 VirtualHost 提供的⽅法, 都需要有⼀个类表示对应的参数
比如创建交换机代码如下:
public class ExchangeDeclareArguments extends BaseArguments implements Serializa
private String exchangeName;
private ExchangeType exchangeType;
private boolean durable;
private boolean autoDelete;
private Map<String, Object> arguments;
}
⼀个创建交换机的请求,形如:
- 可以把 ExchangeDeclareArguments 转成 byte[],就得到了下列图片的结构.
- 按照 length 长度读取出 payload, 就可以把读到的⼆进制数据转换成ExchangeDeclareArguments 对象.
后续相关方法也是如此,这里就进行书写了
不一样的一个方法就是 订阅消息的方法,在这里面我们有一个参数为我们的回调函数。
这个回调函数, 是不能通过网络传输的。站在 broker server 这边, 针对消息的处理回调, 其实是统一的。(把消息返回给客户端)
客户端这边收到消息之后, 再在客户端自己这边执行一个用户自定义的回调就行了。此时, 客户端也就不需要把自身的回调告诉给服务器了.
因此这个类就不需要 consumer 成员了
🌳定义其他返回类
这个返回类是因为,我们需要执行回调函数将消息发送给客户端(订阅方)、
代码执行如下:
public class SubScribeReturns extends BasicReturns implements Serializable {
private String consumerTag;
private BasicProperties basicProperties;
private byte[] body
//省略get与set
}
⭕总结
关于《【消息队列开发】 设计网络通信协议》就讲解到这儿,感谢大家的支持,欢迎各位留言交流以及批评指正,如果文章对您有帮助或者觉得作者写的还不错可以点一下关注,点赞,收藏支持一下