MQTT服务器

前言

看完了MQTT协议,想做个简单的实验,于是一顿搜索。初看发现了EMQX(emqttd)、Mosquitto开源实现,后对比发现MQTT Broker真是一个大宝藏,它要解决以下几个问题:

  1. 连接管理 => Reactor、Golang CSP
  2. 权限管理
  3. 协议的解析与应答 => 通信协议
  4. 数据的存储 => 分布式存储
  5. 集群方案 => 一致性、raft

这几个问题基本涵盖了分布式领域的核心问题,这很值得去好好研究一番。

各家言论存储方式EMQ部署架构

还有一个客户端的问题,手机端获取数据使用MQTT协议还是HTTP更好一些?

首先是都可以:

性能上看:MQTT在线推数据会更好,否则就需要搭配消息服务来进行推送,数据经过的节点增多,带来性能上、稳定性、复杂度上的损失;对于离线数据倒是差距不大,先缓存,然后client去拉取即可,这种复杂度更低一些。

开发难易度上看:这要综合前端、手机端、后端来看,如果已经有消息服务,走消息服务的路子开发容易一些,如果没有更应该使用MQTT了。

综合对比,还是使用MQTT更好一些,如果不需要推送,或对推送要求不高,到可以使用HTTP。

技术难度与应收之间的关系:太难的并不一定应收更高

TCP与UDP、Java与Go,这隐含着否定之否定的关系

确定语言:C/C++ 或 Go

体验EMQX

环境

使用了emqx与对应的mqttx客户端;

docker pull emqx/emqx:5.0.3

docker run -d --name emqx -p 1883:1883 -p 8083:8083 -p 8084:8084 -p 8883:8883 -p 18083:18083 emqx/emqx:5.0.3

127.0.0.1:18083

user: admin

password: public

下载mqttx并安装

MQTT报文分析

参考

使用sudo tcpdump -i any -nn -X port 1883查看了MQTT的报文,用这种方式看不到二层的头(可以通过 tcpdump port 1883 -e -XX -S来看二层的头)

这里是从IP层开始的(红色):

对应IP头格式来看,
Version:0x4,IHL:0x5,
所以这是一个IPV4报文,同时IP头长度是5个UINT32,也就是20字节。

Total Length:0x68 = 104(DEC)
104字节是从IP头开始之后的报文总长度,IP头占了20,也就是说后面的TCP头+data一共84字节。

Identification + Flags + Fragment Offset:0x314d 4000
这一行是分片时才会起作用的字段,这里报文长度太短,达不到MTU,暂不分析。

Time to Live: 0x40,Protocol:0x06
TTL是0x40,也就是128,这个值只有在经过一个路由器时,才减一。我的两个设备在同一个局域网下,相当于二层互通,所以根本用不上路由器转发,这个值就是初始值,没有减一过。
Protocol是6代表下一层协议是TCP。

Header CheckSum:0x0b41,奇偶校验和

Source Address:7f00 0001,127.0.0.1

Destination Address:7f00 0001,127.0.0.1

IP报文

再来看看TCP报文(黄色):

Source Port:e284,Destination Port:075b
源端口号0xe284 = 57988(DEC),目的端口号0x075b = 1883(DEC)。

Sequence Number:0xda2e a080,Acknowledgment Number:0x27ce d5e9
seqNumber是报文的发送方发送的报文序列号,每发送一个就加一。
AckNumber是报文的发送方请求应答方发送的报文序列号。

Dataoffset:0x8,Reserved(6 Bits): 000000,Flag(6Bits):0x18 = 011000,
dataoffset表示tcp头部长度是8个UINT32,也就是32字节,跟IP头部的IHL类似。
Reserved必须填0,保留字段,暂时没用,可能后续会有扩展的用途吧
Flag有6个bit

Window:0x0200。指示接收方的当前缓冲区大小,指明了能够一次接收多少字节的报文。

Checksum:0xfe5c
checksum是与ip头中的header checksum功能类似,校验用

Urgent Pointer:0x0000,配合URG标记置一才会有用处

tcp头的固定长度一般也是20字节,但这里却是32字节,后边12字节(0101 080a 8e18 5449 8e17 b392)暂时未知。

最后看看MQTT的报文:0x3232:

消息类型:0x3,代表消息类型,PUBLISH消息

后边四位是0x2,代表QoS是2,且没有重复,不需要保留消息

后两位0x32,代表消息体32字节

通过对比报文这里的0x6d79,是utf-8的my,也就是数据的开头,但之前有个0x0017,这个也没有搞清楚。

Mosquito源码结构

主循环

image-20220722160824021

connect与publish

image-20220722161043978

有这个过程看,这里的方式就是通过epoll的多路复用来监听各个tcp连接,然后分别来进行处理的过程。

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×