久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 2666|回復: 1
打印 上一主題 下一主題
收起左側

MQTT底層封包協議

[復制鏈接]
跳轉到指定樓層
樓主
ID:471375 發表于 2020-6-26 15:31 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式
MQTT(Message Queuing Telemetry Transport,消息隊列遙測傳輸協議),是一種基于發布/訂閱(publish/subscribe)模式的"輕量級"通訊協議,該協議構建于TCP/IP協議上,由IBM在1999年發布。MQTT最大優點在于,可以以極少的代碼和有限的帶寬,為連接遠程設備提供實時可靠的消息服務。作為一種低開銷、低帶寬占用的即時通訊協議,使其在物聯網、小型設備、移動應用等方面有較廣泛的應用。
在基于C的封包底層上有許多比較精妙的地方,可以參考看一看
  1. /**
  2.   ******************************************************************************
  3.   * @version V1.0.0
  4.   * @date    2019/12/15
  5.   * @brief   
  6.   ******************************************************************************
  7.        
  8.   ******************************************************************************
  9.   */

  10. #define MQTTCLIENT_C_//如果沒有定義

  11. #include "mqtt_msg.h"
  12. #include "string.h"
  13. #include "stm32f10x.h"


  14. #define MQTT_MAX_FIXED_HEADER_SIZE 3

  15. uint16_t mqtt_message_id = 0;

  16. enum mqtt_connect_flag
  17. {
  18.   MQTT_CONNECT_FLAG_USERNAME = 1 << 7,
  19.   MQTT_CONNECT_FLAG_PASSWORD = 1 << 6,
  20.   MQTT_CONNECT_FLAG_WILL_RETAIN = 1 << 5,
  21.   MQTT_CONNECT_FLAG_WILL = 1 << 2,
  22.   MQTT_CONNECT_FLAG_CLEAN_SESSION = 1 << 1
  23. };
  24. //__attribute((__packed__))
  25. struct  mqtt_connect_variable_header
  26. {
  27.   uint8_t lengthMsb;
  28.   uint8_t lengthLsb;
  29.   uint8_t magic[4];
  30.   uint8_t version;
  31.   uint8_t flags;
  32.   uint8_t keepaliveMsb;
  33.   uint8_t keepaliveLsb;
  34. };


  35. int mqtt_get_type(char* buffer) { return (buffer[0] & 0xf0) >> 4; }
  36. int mqtt_get_connect_ret_code(char* buffer) { return (buffer[3]); }
  37. int mqtt_get_qos(char* buffer) { return (buffer[0] & 0x06) >> 1; }


  38. int append_string(int *length, char* buffer,int buffer_length, char* string, int len)
  39. {
  40.   if((*length) + len + 2 > buffer_length)//加上 ClientID 和 記錄 ClientID個數(兩位) 以后超出了數組
  41.     return -1;

  42.   buffer[(*length)++] = len >> 8;
  43.   buffer[(*length)++] = len & 0xff;
  44.   c_memcpy(buffer + (*length), string, len);
  45.   (*length) += len;
  46.   return len + 2;
  47. }



  48. uint16_t append_message_id(int *length, char* buffer,int buffer_length, uint16_t message_id)
  49. {
  50.   // If message_id is zero then we should assign one, otherwise
  51.   // we'll use the one supplied by the caller
  52.   while(message_id == 0)
  53.     message_id = ++mqtt_message_id;

  54.   if((*length) + 2 > buffer_length)
  55.     return 0;

  56.   buffer[(*length)++] = message_id >> 8;
  57.   buffer[(*length)++] = message_id & 0xff;
  58.        
  59.   return message_id;
  60. }


  61. int fini_message(char **data_ptr,int        length,char* buffer, int type, int dup, int qos, int retain)
  62. {
  63.   int remaining_length = length - MQTT_MAX_FIXED_HEADER_SIZE;
  64.        
  65.   if(remaining_length > 127)
  66.   {
  67.     buffer[0] = ((type & 0x0f) << 4) | ((dup & 1) << 3) | ((qos & 3) << 1) | (retain & 1);
  68.     buffer[1] = 0x80 | (remaining_length % 128);
  69.     buffer[2] = remaining_length / 128;
  70.     length = remaining_length + 3;
  71.     *data_ptr = buffer;
  72.   }
  73.   else
  74.   {
  75.     buffer[1] = ((type & 0x0f) << 4) | ((dup & 1) << 3) | ((qos & 3) << 1) | (retain & 1);
  76.     buffer[2] = remaining_length;
  77.     length = remaining_length + 2;
  78.     *data_ptr = buffer + 1;
  79.   }

  80.   return length;
  81. }



  82. uint16_t mqtt_get_id(char* buffer, uint16_t length)
  83. {
  84.   if(length < 1)
  85.     return 0;
  86.        
  87.   switch(mqtt_get_type(buffer))
  88.   {
  89.     case MQTT_MSG_TYPE_PUBLISH:
  90.     {
  91.       int i;
  92.       int topiclen;

  93.       for(i = 1; i < length; ++i)
  94.       {
  95.         if((buffer[i] & 0x80) == 0)
  96.         {
  97.           ++i;
  98.           break;
  99.         }
  100.       }

  101.       if(i + 2 >= length)
  102.         return 0;
  103.       topiclen = buffer[i++] << 8;
  104.       topiclen |= buffer[i++];

  105.       if(i + topiclen >= length)
  106.         return 0;
  107.       i += topiclen;

  108.       if(mqtt_get_qos(buffer) > 0)
  109.       {
  110.         if(i + 2 >= length)
  111.           return 0;
  112.         //i += 2;
  113.       } else {
  114.               return 0;
  115.       }
  116.       return (buffer[i] << 8) | buffer[i + 1];
  117.     }
  118.     case MQTT_MSG_TYPE_PUBACK:
  119.     case MQTT_MSG_TYPE_PUBREC:
  120.     case MQTT_MSG_TYPE_PUBREL:
  121.     case MQTT_MSG_TYPE_PUBCOMP:
  122.     case MQTT_MSG_TYPE_SUBACK:
  123.     case MQTT_MSG_TYPE_UNSUBACK:
  124.     case MQTT_MSG_TYPE_SUBSCRIBE:
  125.     {
  126.       // This requires the remaining length to be encoded in 1 byte,
  127.       // which it should be.
  128.       if(length >= 4 && (buffer[1] & 0x80) == 0)
  129.         return (buffer[2] << 8) | buffer[3];
  130.       else
  131.         return 0;
  132.     }

  133.     default:
  134.       return 0;
  135.   }
  136. }






  137. /**
  138. * @brief   打包連接MQTT指令
  139. * @param   info     MQTT信息
  140. * @param   data_ptr 打包的數據首地址
  141. * @param   buffer   打包進的數組
  142. * @param   buffer_length 數組長度
  143. * @retval  數據長度
  144. * @warning None
  145. * @example
  146. **/
  147. int mqtt_msg_connect(mqtt_connect_info_t* info,char **data_ptr,char* buffer,int buffer_length)
  148. {
  149.         int length;
  150.   struct mqtt_connect_variable_header* variable_header;
  151.        
  152.         mqtt_message_id = 0;
  153.        
  154.         length = MQTT_MAX_FIXED_HEADER_SIZE;//頭.連接類型1位,數據個數2位(如果大于127就需要兩位)
  155.        
  156.   if(length + sizeof(*variable_header) > buffer_length)//數組不夠存儲的
  157.     return 0;
  158.        
  159.   variable_header = (void*)(buffer + length);//把數組分給這個結構體里面的變量
  160.   length += sizeof(*variable_header);//存儲完 連接類型,整個數據個數,版本號個數,版本號,等
  161.        
  162.   variable_header->lengthMsb = 0;//版本名稱個數高位
  163.   variable_header->lengthLsb = 4;//版本名稱個數低位
  164.   c_memcpy(variable_header->magic, "MQTT", 4);//版本名稱MQTT
  165.   variable_header->version = 4;//版本號
  166.   variable_header->flags = 0;//先清零
  167.   variable_header->keepaliveMsb = info->keepalive >> 8;//心跳包時間
  168.   variable_header->keepaliveLsb = info->keepalive & 0xff;//心跳包時間

  169.   if(info->clean_session)//清除連接信息
  170.     variable_header->flags |= MQTT_CONNECT_FLAG_CLEAN_SESSION;

  171.   if(info->client_id != NULL && info->client_id[0] != '\0')//client_id
  172.   {
  173.     if(append_string(&length,buffer,buffer_length, info->client_id, c_strlen(info->client_id)) < 0)//拷貝
  174.       return -1;//數組不夠用呀...
  175.   }
  176.   else
  177.     return -2;//沒有設置client_id

  178.   if(info->will_topic != NULL && info->will_topic[0] != '\0')//遺囑
  179.   {
  180.     if(append_string(&length,buffer,buffer_length , info->will_topic, c_strlen(info->will_topic)) < 0)//遺囑的主題
  181.       return -3;

  182.     if(append_string(&length,buffer,buffer_length , info->will_message, c_strlen(info->will_message)) < 0)//遺囑的消息
  183.       return -4;

  184.     variable_header->flags |= MQTT_CONNECT_FLAG_WILL;//需要遺囑
  185.     if(info->will_retain)//遺囑是夠需要服務器保留
  186.       variable_header->flags |= MQTT_CONNECT_FLAG_WILL_RETAIN;//保留遺囑
  187.     variable_header->flags |= (info->will_qos & 3) << 3;//遺囑消息等級
  188.   }

  189.   if(info->username != NULL && info->username[0] != '\0')//username
  190.   {
  191.     if(append_string(&length,buffer,buffer_length, info->username, c_strlen(info->username)) < 0)//拷貝用戶名
  192.       return -5;

  193.     variable_header->flags |= MQTT_CONNECT_FLAG_USERNAME;//有用戶名
  194.   }
  195.        
  196.   if(info->password != NULL && info->password[0] != '\0')//password
  197.   {
  198.     if(append_string(&length,buffer,buffer_length, info->password, c_strlen(info->password)) < 0)
  199.       return -6;

  200.     variable_header->flags |= MQTT_CONNECT_FLAG_PASSWORD;//有密碼
  201.   }

  202.   return fini_message(data_ptr,length, buffer, MQTT_MSG_TYPE_CONNECT, 0, 0, 0);//最終組合連接MQTT的指令
  203. }


  204. /**
  205. * @brief  判斷是否連接上MQTT
  206. * @param  服務器返回的數據
  207. * @param  
  208. * @retval 0 連接成功
  209. * @example
  210. **/
  211. int  mqtt_msg_connect_ack(char *buff)
  212. {
  213.         if(mqtt_get_type(buff) == MQTT_MSG_TYPE_CONNACK)
  214.         {
  215.                 return mqtt_get_connect_ret_code(buff);
  216.         }
  217.         return -1;
  218. }


  219. /**
  220. * @brief   斷開連接
  221. * @param   data_ptr 打包的數據首地址
  222. * @param   buffer   打包進的數組
  223. * @param   buffer_length 數組長度
  224. * @retval  數據長度
  225. * @warning None
  226. * @example
  227. **/
  228. int mqtt_msg_disconnect(char **data_ptr,char* buffer,int buffer_length)
  229. {
  230.         int length;
  231.         length = MQTT_MAX_FIXED_HEADER_SIZE;
  232.   return fini_message(data_ptr,length, buffer, MQTT_MSG_TYPE_DISCONNECT, 0, 0, 0);
  233. }



  234. /**
  235. * @brief   訂閱主題
  236. * @param   topic   訂閱的主題
  237. * @param   qos     消息等級
  238. * @param   data_ptr 打包的數據首地址
  239. * @param   buffer   打包進的數組
  240. * @param   buffer_length 數組長度
  241. * @retval  數據長度
  242. * @warning None
  243. * @example
  244. **/
  245. int mqtt_msg_subscribe_topic(char* topic, int qos,char **data_ptr,char* buffer,int buffer_length)
  246. {
  247.         int length;
  248.         length = MQTT_MAX_FIXED_HEADER_SIZE;
  249.        
  250.         if(topic == NULL || topic[0] == '\0')
  251.                 return -1;
  252.        
  253.         if((mqtt_message_id = append_message_id(&length, buffer, buffer_length, 0)) == 0)
  254.                 return -2;
  255.        
  256.         if(append_string(&length, buffer, buffer_length, topic, c_strlen(topic)) < 0)
  257.                 return -3;
  258.        
  259.         if(length + 1 > buffer_length)
  260.     return -4;
  261.   buffer[length++] = qos;
  262.        
  263.         return fini_message(data_ptr,length, buffer, MQTT_MSG_TYPE_SUBSCRIBE, 0, 1, 0);
  264. }



  265. /**
  266. * @brief  判斷是否成功訂閱
  267. * @param  buffer  服務器返回的數據
  268. * @param  length  服務器返回的數據長度
  269. * @retval 0:成功  1:失敗
  270. * @example
  271. **/
  272. int mqtt_msg_subscribe_ack(char* buffer, uint16_t length)
  273. {
  274.         if(mqtt_get_type(buffer) == MQTT_MSG_TYPE_SUBACK)
  275.         {
  276.                 if(mqtt_get_id(buffer,length) == mqtt_message_id)
  277.                 {
  278.                         return 0;
  279.                 }
  280.                 else
  281.                 {
  282.                         return 1;
  283.                 }
  284.         }
  285.         else
  286.         {
  287.                 return 1;
  288.         }
  289. }


  290. /**
  291. * @brief   發布消息
  292. * @param   topic    主題
  293. * @param   data     消息
  294. * @param   data_length 消息長度
  295. * @param   qos      消息等級
  296. * @param   retain   是否需要保留消息
  297. * @param   data_ptr 打包的數據首地址
  298. * @param   buffer   打包進的數組
  299. * @param   buffer_length 數組長度
  300. * @retval  數據長度
  301. * @warning None
  302. * @example
  303. **/
  304. int mqtt_msg_publish(char* topic, char* date, int data_length, int qos, int retain, char **data_ptr,char* buffer,int buffer_length)
  305. {
  306.         int length;
  307.         length = MQTT_MAX_FIXED_HEADER_SIZE;

  308.   if(topic == NULL || topic[0] == '\0')
  309.     return -1;

  310.   if(append_string(&length, buffer, buffer_length, topic, strlen(topic)) < 0)
  311.     return -2;

  312.   if(qos > 0)
  313.   {
  314.     if((mqtt_message_id = append_message_id(&length, buffer, buffer_length,  0)) == 0)
  315.       return -3;
  316.   }
  317.   else
  318.     mqtt_message_id = 0;

  319.   if(length + data_length > buffer_length)
  320.     return -4;
  321.   memcpy(buffer + length, date, data_length);
  322.   length += data_length;

  323.   return fini_message(data_ptr,length, buffer, MQTT_MSG_TYPE_PUBLISH, 0, qos, retain);
  324. }



  325. int mqtt_msg_puback(uint16_t message_id,char **data_ptr,char* buffer,int buffer_length)
  326. {
  327.         int length;
  328.   length = MQTT_MAX_FIXED_HEADER_SIZE;
  329.   if(append_message_id(&length, buffer, buffer_length,message_id) == 0)
  330.     return -1;
  331.   return fini_message(data_ptr,length, buffer, MQTT_MSG_TYPE_PUBACK, 0, 0, 0);
  332. }


  333. int mqtt_msg_pubrec(uint16_t message_id,char **data_ptr,char* buffer,int buffer_length)
  334. {
  335.         int length;
  336.   length = MQTT_MAX_FIXED_HEADER_SIZE;
  337.   if(append_message_id(&length, buffer, buffer_length,message_id) == 0)
  338.     return -1;
  339.   return fini_message(data_ptr,length, buffer, MQTT_MSG_TYPE_PUBREC, 0, 0, 0);
  340. }


  341. int mqtt_msg_pubrel(uint16_t message_id,char **data_ptr,char* buffer,int buffer_length)
  342. {
  343.         int length;
  344.   length = MQTT_MAX_FIXED_HEADER_SIZE;
  345.        
  346.   if(append_message_id(&length, buffer, buffer_length,message_id) == 0)
  347.     return -1;
  348.   return fini_message(data_ptr,length, buffer, MQTT_MSG_TYPE_PUBREL, 0, 1, 0);
  349. }


  350. int mqtt_msg_pubcomp(uint16_t message_id,char **data_ptr,char* buffer,int buffer_length)
  351. {
  352.         int length;
  353.   length = MQTT_MAX_FIXED_HEADER_SIZE;
  354.   if(append_message_id(&length, buffer, buffer_length,message_id) == 0)
  355.     return -1;
  356.   return fini_message(data_ptr,length, buffer, MQTT_MSG_TYPE_PUBCOMP, 0, 0, 0);
  357. }


  358. const char* mqtt_get_publish_topic(char* buffer, uint16_t* length)
  359. {
  360.   int i;
  361.   int totlen = 0;
  362.   int topiclen;

  363.   for(i = 1; i < *length; ++i)
  364.   {
  365.     totlen += (buffer[i] & 0x7f) << (7 * (i -1));
  366.     if((buffer[i] & 0x80) == 0)
  367.     {
  368.       ++i;
  369.       break;
  370.     }
  371.   }
  372.   totlen += i;

  373.   if(i + 2 >= *length)
  374.     return NULL;
  375.   topiclen = buffer[i++] << 8;
  376.   topiclen |= buffer[i++];

  377.   if(i + topiclen > *length)
  378.     return NULL;

  379.   *length = topiclen;
  380.   return (const char*)(buffer + i);
  381. }


  382. const char* mqtt_get_publish_data(char* buffer, uint16_t* length)
  383. {
  384.   int i;
  385.   int totlen = 0;
  386.   int topiclen;
  387.   int blength = *length;
  388.   *length = 0;

  389.   for(i = 1; i < blength; ++i)
  390.   {
  391.     totlen += (buffer[i] & 0x7f) << (7 * (i - 1));
  392.     if((buffer[i] & 0x80) == 0)
  393.     {
  394.       ++i;
  395.       break;
  396.     }
  397.   }
  398.   totlen += i;

  399.   if(i + 2 >= blength)
  400.     return NULL;
  401.   topiclen = buffer[i++] << 8;
  402.   topiclen |= buffer[i++];

  403.   if(i + topiclen >= blength)
  404.     return NULL;

  405.   i += topiclen;

  406.   if(mqtt_get_qos(buffer) > 0)
  407.   {
  408.     if(i + 2 >= blength)
  409.       return NULL;
  410.     i += 2;
  411.   }

  412.   if(totlen < i)
  413.     return NULL;

  414.   if(totlen <= blength)
  415.     *length = totlen - i;
  416.   else
  417.     *length = blength - i;
  418.   return (const char*)(buffer + i);
  419. }

  420. /**
  421. * @brief   打包服務器返回的心跳包數據(用不到)
  422. * @param   data_ptr 打包的數據首地址
  423. * @param   buffer   打包進的數組
  424. * @param   buffer_length 數組長度
  425. * @retval  數據長度
  426. * @warning None
  427. * @example
  428. **/
  429. int mqtt_msg_pingresp(char **data_ptr,char* buffer,int buffer_length)
  430. {
  431.         int length;
  432.         length = MQTT_MAX_FIXED_HEADER_SIZE;       
  433.   return fini_message(data_ptr,length, buffer, MQTT_MSG_TYPE_PINGRESP, 0, 0, 0);
  434. }

  435. /**
  436. * @brief   獲取發送給服務器的心跳包數據
  437. * @param   data_ptr 打包的數據首地址
  438. * @param   buffer   打包進的數組
  439. * @param   buffer_length 數組長度
  440. * @retval  數據長度
  441. * @warning None
  442. * @example
  443. **/
  444. int mqtt_msg_pingreq(char **data_ptr,char* buffer,int buffer_length)
  445. {
  446.         int length;
  447.         length = MQTT_MAX_FIXED_HEADER_SIZE;       
  448.   return fini_message(data_ptr,length, buffer, MQTT_MSG_TYPE_PINGREQ, 0, 0, 0);
  449. }


復制代碼



MQTT封包解包底層(C語言).zip

4.14 KB, 下載次數: 28, 下載積分: 黑幣 -5

分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏 分享淘帖 頂 踩
回復

使用道具 舉報

沙發
ID:767423 發表于 2020-7-7 13:00 | 只看該作者
資料不錯,下來看看。如果來個教程就完美了。
回復

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規則

手機版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術交流QQ群281945664

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: 欧美成人精品一区二区男人看 | 美女黄网站视频免费 | 日本五月婷婷 | 在线成人 | 免费人成在线观看网站 | 黑人一级片视频 | 精品国产视频 | 欧美日韩在线一区二区 | 人人天天操| 91精品国产综合久久婷婷香蕉 | 亚洲视频在线播放 | 天天草天天操 | av中文字幕在线观看 | 老外几下就让我高潮了 | 婷婷综合激情 | 亚洲啊v在线 | www.99re | 成人av网站在线观看 | 国产一区二 | 成人在线免费观看 | 亚洲乱码国产乱码精品精的特点 | 欧洲精品码一区二区三区免费看 | 91精品麻豆日日躁夜夜躁 | 99精品久久 | 亚洲欧美日韩国产综合 | 在线一区二区国产 | 色视频在线播放 | wwwww在线观看| 亚洲一区二区精品视频在线观看 | 黄色一级片aaa | 91免费入口| 国产亚洲一区二区精品 | 999热视频 | 爱爱小视频 | 特黄色一级毛片 | 亚洲精品乱码久久久久久按摩观 | 精品中文字幕久久 | 视频二区在线观看 | 国产一区二区精品在线 | 在线日韩视频 | 亚洲午夜精品一区二区三区 |