ESA2GJK1DH1K Basics:! Come thorough look MQTT

 

 

First thing you need to know on what MQTT not tall, it's just a software, the software is a fact is a TCP server

First, since it is a TCP server, TCP server and this is what we usually do not do the same.

  First, when we do the usual TCP server is one or more clients connected to the server TCP we do, then the TCP server processes the client data.

  Now it! Requirements have changed!

  Suppose I have five network devices, three mobile phones. I now want to pass remote data network equipment phone. And I need to record data network device to upload.

  Communication is such a hypothesis (and the latter will not stop the increase in equipment and mobile phones)

  

 

 

Second, the supposed ???

  1. The need to record the data of all devices

  2. The presence of many-to-many and between devices and mobile phones

  Therefore, you must require a public server for data transfer.

  Assuming that put the server made a TCP server, someone asked, Why do not you make it UDP? UDP data sent his sister's bad judgment is not sent successfully. Do I always let the server

  Give me back the data fails, I still find some less hassle!

  There is to achieve long-range, there is a public IP network can, you can buy your own server, the network company pulling a private network

  Or to use their own computers, maps with peanut shells

  Or use cloud server it! Is running on someone else's server is a computer (that is, a computer), IP address is a public network directly. Convenient.

 

Third, how to design the TCP server ???

  1. In response to this communication, the first device sends data alone can never be data, something must be added

  2. If the data is sent to bring identifiers? 1 assume that the data is transmitted by the device (aaaaa data) aaaaa is data identification, followed by real data

  3. Then it! 1 on the assumption that the phone is receiving data identification aaaaa data, how to make server forwards it to do ???

  4. If the phone 1 tell when connecting over TCP server, TCP server I receive data identification data is aaaaa

  5. By the above manner is not a bit of the brow ????

  Then we shall say, "I told TCP server receives data identification data is aaaaa" The thing of it, a name is subscribed threads aaaaa

  把 "假设设备1发送的数据是   (aaaaa数据 )"    消息前面的 aaaaa 叫做 发布的主题是aaaaa

 

四,总结上面的就是

  手机1先连接TCP服务器,然后呢,规定个协议,告诉TCP服务器我订阅的主题是aaaaa

  这样呢服务器就记住了,当出现消息前面的主题是aaaaa的消息的时候,他就把这个消息发给手机1

 

  当然咱假设,设备1连接上TCP服务器,然后,告诉TCP服务器我订阅的主题是wwww

  这样呢服务器就记住了,当出现消息前面的主题是wwww的消息的时候,他就把这个消息发给设备1

 

  然后设备1连接上TCP服务器以后呢,这样发送信息(假设发送的消息是123456):   aaaaa1123456

  服务器一接收到客户端的消息,就取出来这个消息的标识是什么,取出来的是 aaaaa

  然后呢,轮训下记录的谁需要消息标识是aaaaa的消息,然后找到了手机1

  最后把这个消息发送给手机1这个客户端,然后手机1就接收到了1123456这个消息

 

  同理:手机1发送  wwww998877  然后这个消息就会发给设备1 ,设备1就会收到 998877

 

  不知道听没听懂!!!没有做过TCP服务器的你先做个TCP服务器和一个客户端试一试通信.....

 

五,总结

  这个服务器道理上是这样,服务器记录各个设备的信息,各个设备订阅的主题,然后呢,判断这个消息然后进行转发

  但是...做个简单的完全可以做出来,但是要想做的完善,而且要支持庞大消息数量的设备(来个百万级).....不是一朝一夕就可以的.

  其实很长时间以前,人们就有这种需求了.多对一和一对多通信

  所以呢,一些组织和单位就开始解决这种问题,开始做这种软件,所以MQTT就诞生了.

  之所以叫MQTT是因为是外国人做的这种TCP服务器,外国人呢,为实现这种功能的TCP取了个名字叫

  Message Queuing Telemetry Transport

  然后取每个首字母  就叫 MQTT了

  其实有很多家做MQTT软件,但是呢,我比较喜欢用emqtt

  

看看怎么连接上他们做的MQTT软件

一,首先咱知道就是个TCP服务器,所以呢,需要先用TCP连接上他们的服务器.

二,然后需要发送第一条消息(注:并不是上来就可以订阅主题的)

  MQTT软件规定呢,你发送的第一条信息是连接信息(相当于咱要先登录)

  他规定呢!

  ClientID: 各个客户端必须设定一个ID,各个客户端必须都不一样               假设是 123456

  用户名: 咱安装MQTT软件的时候可以设置MQTT软件的登录的用户名     假设是yang

  密码: 咱安装MQTT软件的时候可以设置MQTT软件的登录的密码             假设是 11223344

  下面是我当初研究MQTT的协议,写的,然后把上面三个参数填进去

  注意这节我粘贴的代码是当时为了移植到51单片机而自己写的(51内存太少了),咱用32哈,直接用的官方提供的库.

/**
* @brief  连接服务器的打包函数
* @param  
* @retval 
* @example 
**/
int ConnectMqtt(char *ClientID,char *Username,char *Password)
{
    int ClientIDLen = strlen(ClientID);
    int UsernameLen    = strlen(Username);
    int PasswordLen = strlen(Password);
    int DataLen = 0;
    int Index = 2;
    int i = 0;
    DataLen = 12 + 2+2+ClientIDLen+UsernameLen+PasswordLen;
    MqttSendData[0] = 0x10;                //MQTT Message Type CONNECT
    MqttSendData[1] = DataLen;    //剩余长度(不包括固定头部)
    MqttSendData[Index++] = 0;        // Protocol Name Length MSB    
    MqttSendData[Index++] = 4;        // Protocol Name Length LSB    
    MqttSendData[Index++] = 'M';        // ASCII Code for M    
    MqttSendData[Index++] = 'Q';        // ASCII Code for Q    
    MqttSendData[Index++] = 'T';        // ASCII Code for T    
    MqttSendData[Index++] = 'T';        // ASCII Code for T    
    MqttSendData[Index++] = 4;        // MQTT Protocol version = 4    
    MqttSendData[Index++] = 0xc2;        // conn flags 
    MqttSendData[Index++] = 0;        // Keep-alive Time Length MSB    
    MqttSendData[Index++] = 60;        // Keep-alive Time Length LSB  60S心跳包  
    MqttSendData[Index++] = (0xff00&ClientIDLen)>>8;// Client ID length MSB    
    MqttSendData[Index++] = 0xff&ClientIDLen;    // Client ID length LSB  

    for(i = 0; i < ClientIDLen; i++)
    {
        MqttSendData[Index + i] = ClientID[i];          
    }
    Index = Index + ClientIDLen;
    
    if(UsernameLen > 0)
    {   
        MqttSendData[Index++] = (0xff00&UsernameLen)>>8;//username length MSB    
        MqttSendData[Index++] = 0xff&UsernameLen;    //username length LSB    
        for(i = 0; i < UsernameLen ; i++)
        {
            MqttSendData[Index + i] = Username[i];    
        }
        Index = Index + UsernameLen;
    }
    
    if(PasswordLen > 0)
    {    
        MqttSendData[Index++] = (0xff00&PasswordLen)>>8;//password length MSB    
        MqttSendData[Index++] = 0xff&PasswordLen;    //password length LSB    
        for(i = 0; i < PasswordLen ; i++)
        {
            MqttSendData[Index + i] = Password[i];    
        }
        Index = Index + PasswordLen; 
    }    
    return Index;
}

 

得到以下数据,然后把这个数据发给TCP 服务器,如果没有错误,服务器就会回 90 02 00 00

10 22 00 04 4D 51 54 54 04 C2 00 03 00 06 31 32 33 34 35 36 00 04 79 61 6E 67 00 08 31 31 32 32 33 33 34 34

先说一件事情  所有的MQTT数据哈  第一个数据是说明整个数据是干什么的数据   第二个是说它后面的数据的总个数

10 : 固定,MQTT规定的连接用0x10

22: 是说0x22后面有0x22个数据  34个

00 04: 后面记录MQTT版本号的字节个数  

4D 51 54 54: M Q T T  版本号字符         这个是4版本,不同版本不一样 3版本的是MQIsdp 额,了解就可以

04: 版本号是 0x04 

C2:这个呢想了解具体呢,需要看协议  http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718028

 

 

我说一下哈,不要去纠结这个协议,你再怎么研究也没大用,官方早就给咱准备好了各种平台的包.咱要做的是熟练运用.

上面就是说有用户名和密码,每次连接的时候清除连接信息,没有设置遗嘱(后面会说)

00 03: 心跳包是3S一次(这个自己连接的时候自己设置),

MQTT规定必须客户端必须发心跳包,客户端发送的心跳包数据是 0xC0 0x00,这是MQTT规定的

如果心跳包间隔了你设定心跳包的1.5倍时间,你没有发给服务器,服务器就认为你掉线了,然后还有个遗嘱问题,,后面会说

你发给服务器 0xC0 0x00  服务器会回你 0xD0  0x00  这个知道就行了

 

00 06:客户端的ClientId有6位

后面的  31 32 33 34 35 36    就是ClientId ,这是MQTT服务器规定的,每隔客户端必须有各自的ClientId

 

00 04: MQTT的用户名  

79 61 6E 67  我安装MQTT的时候设置的MQTT的用户名是yang

 

00 08: MQTT的密码

31 31 32 32 33 33 34 34  我安装MQTT的时候设置的MQTT密码

 

好了,连接上TCP服务器 然后发送

10 22 00 04 4D 51 54 54 04 C2 00 03 00 06 31 32 33 34 35 36 00 04 79 61 6E 67 00 08 31 31 32 32 33 33 34 34

服务器呢就会回你  90 02 00 00

90: 固定

02: 后面有两个数据

后面的两个数据呢,有几个返回值,0就说明成功,其它就是有各种问题

比如说回的是 90 02 00 04  就说明用户名或者密码有问题.

 

 

 

 

现在服务器认咱了,该告诉服务器我订阅的主题了

假设告诉服务器我订阅的是2222

假设订阅的时候订阅的主题的消息标识是1,消息等级是0

那么打包以后就是 82 09 00 01 00 04 32 32 32 32 00  然后把这个数据发给TCP服务器

 

/**
* @brief  MQTT订阅/取消订阅数据打包函数
* @param  SendData 
* @param  topic                主题 
* @param  qos         消息等级 
* @param  whether     订阅/取消订阅请求包
* @retval 
* @example 
**/
int MqttSubscribeTopic(char *topic,u8 qos,u8 whether)
{    
    int topiclen = strlen(topic);
    int i=0,index = 0;
  
    if(whether)
        MqttSendData[index++] = 0x82;                        //0x82 //消息类型和标志 SUBSCRIBE 订阅
    else
        MqttSendData[index++] = 0xA2;                        //0xA2 取消订阅
    MqttSendData[index++] = topiclen + 5;                //剩余长度(不包括固定头部)
    MqttSendData[index++] = 0;                          //消息标识符,高位
    MqttSendData[index++] = 0x01;                    //消息标识符,低位
    MqttSendData[index++] = (0xff00&topiclen)>>8;    //主题长度(高位在前,低位在后)
    MqttSendData[index++] = 0xff&topiclen;              //主题长度 
    
    for (i = 0;i < topiclen; i++)
    {
        MqttSendData[index + i] = topic[i];
    }
    index = index + topiclen;
    
    if(whether)
    {
        MqttSendData[index] = qos;//QoS级别
        index++;
    }
    return index;
}

 

 

 

 

0x82: 告诉MQTT服务器,我要订阅主题

0x09: 后面的数据个数

0x00  0x01  注意哈,订阅主题的时候可以设置了标识  标识呢  1-65535

之所以有这个家伙:咱订阅的时候怎么判断订阅成功了呢???

订阅成功以后呢!服务器会返回咱订阅成功的回复,回复里面就包含着咱写的这个标识

咱呢可以对比下这个标识,然后呢就知道到底是不是订阅成功了.

0x00  0x04  后面订阅主题的长度

32 32 32 32 订阅的主题是 2222

最后一个 00 是说消息等级,一般呢,订阅设置为0 就可以

那就说一下这个消息等级有什么用吧!

咱发送数据的时候也会携带一个消息等级

假设是0  那么这条消息是不是真的发给MQTT服务器(Broker)了,就不知道了,

如果设备多个,还真不敢保证真的发给服务器了

 

假设是1 那么一个客户端发送消息以后呢,服务器一看消息等级是1,那么就会回给那个发送消息的客户端一个应答消息

客户端发送完消息以后其实内部会启动一个超时操作,如果多少时间内没有回复,那么他会再发一次

 

假设是2 这个呢就是消息一定要到达MQTT服务器.这个很苛刻,也比较占用内存

 

 

如果按照上面发呢,服务器会回

90 03 00 01 00 

90:固定

03:后面的数据长度

00 01:这条主题的标识

00:消息等级

 

然后看发布

长话短说

发布的时候呢,信息里面都有这些内容

发布的主题,消息,回传标志,消息等级,是不是需要服务器保留消息,消息的标识

/**
* @brief  MQTT发布数据打包函数
* @param  mqtt_message 
* @param  topic                主题 
* @param  qos         消息等级 
* @retval 
* @example 
**/
int MqttPublishData(char * topic, char * message, u8 qos)
{  
    int topic_length = strlen(topic);    
    int message_length = strlen(message);  
    int i,index=0;    
    static u16 id=0;
    
    MqttSendData[index++] = 0x30;    // MQTT Message Type PUBLISH  

  
    if(qos)
        MqttSendData[index++] = 2 + topic_length + 2 + message_length;//数据长度
    else
        MqttSendData[index++] = 2 + topic_length + message_length;   // Remaining length  

  
    MqttSendData[index++] = (0xff00&topic_length)>>8;//主题长度
    MqttSendData[index++] = 0xff&topic_length;
         
    for(i = 0; i < topic_length; i++)
    {
        MqttSendData[index + i] = topic[i];//拷贝主题
    }
    index += topic_length;
        
    if(qos)
    {
        MqttSendData[index++] = (0xff00&id)>>8;
        MqttSendData[index++] = 0xff&id;
        id++;
    }
  
    for(i = 0; i < message_length; i++)
    {
        MqttSendData[index + i] = message[i];//拷贝数据
    }
    index += message_length;
        
    return index;
}

 

发布的主题: 谁订阅了这个主题,消息就传给谁

回传标志: 我没用过,默认0

消息等级:上面说了

是不是需要服务器保留消息:一会和遗嘱一块说

消息的标识:上面有提及,一般用不到,默认1就可以

 

最后看遗嘱

还记得上面

 

 

 

我直接说遗嘱是啥意思哈!

假设我手机和一个设备订阅主题和发布主题对应,我就能和这个设备通信了

但是,我怎么知道这个设备掉线了呢?

当然完全可以自己发信息给那个设备,如果不回复,就说明掉线了

但是呢!MQTT服务器提供了一种方式

假设我设置好设备的遗嘱消息是  offline    遗嘱发布的主题是 aaaaa

如果设备掉线,服务器就会给订阅了aaaaa的客户端发送  offline

 

还记得上面说的不   服务器如果在你设置的心跳包时间的1.5倍收不到心跳包就认为你掉线了.

 

结语

了解就可以,关键是学会使用,就是个安装软件的事情,封包解包也不用你写

官方早就把各种平台的包给你准备好了,我之所以研究,是因为当时要用51单片机做,官方包太大.....没办法只能自己写....

 

Guess you like

Origin www.cnblogs.com/yangfengwu/p/11762642.html