
mqtt协议详解
过亚弥乃-幼儿园食堂
2023年3月20日发(作者:南园小学)mqtt协议分析
mqtt协议分析
⼀.mqtt报⽂
mqtt报⽂包括,固定报头,可变报头,有效载荷(消息体)。
1.固定报头
mqttcontrolpackettype:
flagsspecifictoeachmqttcontrolpackettype:
dup:客户端与服务器消息重发时,此标志被置1
qos:消息质量等级,最多⼀次(QoS0),⾄少⼀次(QoS1),有且仅有⼀次(QoS2)
retain:是否保持此条消息,1为保持
2.可变报头
不同类型消息其参数不⼀样,现在以connect类型为例。
这⾥解释下连接标志与保活计时器
usernameflag:值为1,连接mqtt需要⽤户名,存在于有效载荷⾥
passwordflag:值为1,连接mqtt需要密码,存在于有效载荷⾥
所以,如果连接mqttservice需要⽤户名和密码,这两位需要置1。
willretain,willqos,willflag:控制客户端与服务器异常断开,发送will消息给客户端,如果willflag被置1,willretain与willqos设置将
会被⽣效,并且在有效载荷填写相关字段内容。
保活计时器:客户端设定⼀段时间给服务器发送⼀个ping包,⽤于探测⼆者是否还处于正常连接状态。
3.有效载荷
存放着客户端与服务器之间需要传输的数据,不同消息类型,其携带的数据也不⼀样。
CONNECT:
该有效载荷包含了⼀个或多个UTF-8编码字符串。它们包括标识客户端的唯⼀标识符、Will
主题和消息、要使⽤的⽤户名和密码。其中只有第⼀项是必选的,其余的取决于可变消息头
部中的标志置位情况
SUBSCRIBE:
该有效载荷包含⼀系列要订阅的主题名,以及每个主题的QoS级别。这些字符串都是UTF
编码的。
PUBLISH:
该有效载荷只包含应⽤特定的数据。
⼆.wireshark抓包分析mqtt协议
设备开机,连接mqtt服务器,订阅发布消息,并且定时ping服务器的完整log如下图。
connect报⽂:
报⽂内容解析(补充,与上图不是⼀个mqtt包):
subscribe报⽂:
报⽂内容解析(补充,与上图不是⼀个mqtt包):
publish报⽂:
msglen属于固定报头,mqtt报⽂剩余长度
三.mqtt源码实现
本⽂已CONNECT类型为例,其他都是类似的,封装报⽂,发送数据包;
//封装报⽂
if((len=MQTTSerialize_connect(c->buf,c->buf_size,options))<=0)
gotoexit;
//发送报⽂
if((rc=sendPacket(c,len,&connect_timer))!=SUCCESS)//sendtheconnectpacket
gotoexit;//therewasaproblem
intMQTTSerialize_connect(unsignedchar*buf,intbuflen,MQTTPacket_connectData*options)
{
unsignedchar*ptr=buf;
MQTTHeaderheader={0};
MQTTConnectFlagsflags={0};
intlen=0;
intrc=-1;
FUNC_ENTRY;
if(MQTTPacket_len(len=MQTTSerialize_connectLength(options))>buflen)
{
{
rc=MQTTPACKET_BUFFER_TOO_SHORT;
gotoexit;
}
=0;
=CONNECT;//mqtt包类型
writeChar(&ptr,);/*writeheader*/
ptr+=MQTTPacket_encode(ptr,len);/*writeremaininglength*/
if(options->MQTTVersion==4)//mqtt协议版本
{
writeCString(&ptr,"MQTT");
writeChar(&ptr,(char)4);
}
else
{
writeCString(&ptr,"MQIsdp");
writeChar(&ptr,(char)3);//mqtt协议名称
}
//mqttconnect连接标志
=0;
ession=options->cleansession;
=(options->willFlag)?1:0;
if()
{
S=options->;
tain=options->ed;
}
if(options->g||options->)
me=1;
if(options->g||options->)
rd=1;
writeChar(&ptr,);
writeInt(&ptr,options->keepAliveInterval);//保活计时器
//有效载荷
writeMQTTString(&ptr,options->clientID);
if(options->willFlag)
{
writeMQTTString(&ptr,options->ame);
writeMQTTString(&ptr,options->e);
}
if(me)
writeMQTTString(&ptr,options->username);
if(rd)
writeMQTTString(&ptr,options->password);
rc=ptr-buf;
exit:FUNC_EXIT_RC(rc);
returnrc;
}
本⽂部分内容参考mqtt-v3.1协议规范,可⾃⾏去查看详细内容。