目錄
1. MQTT 協議簡介
MQTT 協議全稱是Message Queuing Telemetry Transport,翻譯過來就是消息隊列遙測傳輸協議,它是物聯網常用的應用層協議,運行在TCP/IP 中的應用層中,依賴TCP 協議,因此它具有非常高的可靠性,同時它是基於TCP 協議的<客戶端-服務器>模型發佈/訂閱主題消息的輕量級協議。
官方: http://mqtt.org/documentation
個人整理:https://blog.csdn.net/XieWinter/article/details/101198750
2. 移植MQTT 協議
因爲MQTT 是應用層協議,基於TCP 協議至少,首先我們就需要把LwIP 協議跑通,我們就使用Socket API 來進行移植。
首先下載MQTT 的源碼庫:
GitHub 相關鏈接:
https://github.com/mqtt/mqtt.github.io/wiki
進入libraries 頁面會發現,有多種語言的支持,選擇所需要的C庫,下載
源碼下載鏈接:https://github.com/eclipse/paho.mqtt.embedded-c
下載的壓縮包,並解壓。
創建 一個MQTT的文件夾,將MQTTPacket\src 目錄下的文件添加到工程目錄MQTT 文件夾,再將MQTTPacket\samples 目錄下的transport.c、transport.h 添加到這個文件夾下,添加完成後文件夾內容如下:
把MQTT 添加到工程,然後實現transport.c 文件的移植層接口。
#include "transport.h"
#include "lwip/opt.h"
#include "lwip/arch.h"
#include "lwip/api.h"
#include "lwip/inet.h"
#include "lwip/sockets.h"
#include "string.h"
static int mysock;
/************************************************************************
** 函數名稱: transport_sendPacketBuffer
** 函數功能: 以TCP方式發送數據
** 入口參數: unsigned char* buf:數據緩衝區
** int buflen:數據長度
** 出口參數: <0發送數據失敗
************************************************************************/
int32_t transport_sendPacketBuffer( uint8_t* buf, int32_t buflen)
{
int32_t rc;
rc = write(mysock, buf, buflen);
return rc;
}
/************************************************************************
** 函數名稱: transport_getdata
** 函數功能: 以阻塞的方式接收TCP數據
** 入口參數: unsigned char* buf:數據緩衝區
** int count:數據長度
** 出口參數: <=0接收數據失敗
************************************************************************/
int32_t transport_getdata(uint8_t* buf, int32_t count)
{
int32_t rc;
//這個函數在這裏不阻塞
rc = recv(mysock, buf, count, 0);
return rc;
}
/************************************************************************
** 函數名稱: transport_open
** 函數功能: 打開一個接口,並且和服務器 建立連接
** 入口參數: char* servip:服務器域名
** int port:端口號
** 出口參數: <0打開連接失敗
************************************************************************/
int32_t transport_open(int8_t* servip, int32_t port)
{
int32_t *sock = &mysock;
int32_t ret;
// int32_t opt;
struct sockaddr_in addr;
//初始換服務器信息
memset(&addr,0,sizeof(addr));
addr.sin_len = sizeof(addr);
addr.sin_family = AF_INET;
//填寫服務器端口號
addr.sin_port = PP_HTONS(port);
//填寫服務器IP地址
addr.sin_addr.s_addr = inet_addr((const char*)servip);
//創建SOCK
*sock = socket(AF_INET,SOCK_STREAM,0);
//連接服務器
ret = connect(*sock,(struct sockaddr*)&addr,sizeof(addr));
if(ret != 0)
{
//關閉鏈接
close(*sock);
//連接失敗
return -1;
}
//連接成功,設置超時時間1000ms
// opt = 1000;
// setsockopt(*sock,SOL_SOCKET,SO_RCVTIMEO,&opt,sizeof(int));
//返回套接字
return *sock;
}
/************************************************************************
** 函數名稱: transport_close
** 函數功能: 關閉套接字
** 入口參數: unsigned char* buf:數據緩衝區
** int buflen:數據長度
** 出口參數: <0發送數據失敗
************************************************************************/
int transport_close(void)
{
int rc;
// rc = close(mysock);
rc = shutdown(mysock, SHUT_WR);
rc = recv(mysock, NULL, (size_t)0, 0);
rc = close(mysock);
return rc;
}
#ifndef __TRANSPORT_H
#define __TRANSPORT_H
#include "stm32f4xx.h"
#include "main.h"
/************************************************************************
** 函數名稱: transport_sendPacketBuffer
** 函數功能: 以TCP方式發送數據
** 入口參數: unsigned char* buf:數據緩衝區
** int buflen:數據長度
** 出口參數: <0發送數據失敗
************************************************************************/
int32_t transport_sendPacketBuffer( uint8_t* buf, int32_t buflen);
/************************************************************************
** 函數名稱: transport_getdata
** 函數功能: 以阻塞的方式接收TCP數據
** 入口參數: unsigned char* buf:數據緩衝區
** int count:數據長度
** 出口參數: <=0接收數據失敗
************************************************************************/
int32_t transport_getdata(uint8_t* buf, int32_t count);
/************************************************************************
** 函數名稱: transport_open
** 函數功能: 打開一個接口,並且和服務器 建立連接
** 入口參數: char* servip:服務器域名
** int port:端口號
** 出口參數: <0打開連接失敗
************************************************************************/
int32_t transport_open(int8_t* servip, int32_t port);
/************************************************************************
** 函數名稱: transport_close
** 函數功能: 關閉套接字
** 入口參數: unsigned char* buf:數據緩衝區
** int buflen:數據長度
** 出口參數: <0發送數據失敗
************************************************************************/
int32_t transport_close(void);
#endif
3. cJSON 移植
見:https://blog.csdn.net/XieWinter/article/details/101049395
4. 例程
實現定時推送信息,手上沒有DHT11 , 直接模擬一個動態數據。通過MQTT FX 發佈消息,接收訂閱解析。