精品国产人成在线_亚洲高清无码在线观看_国产在线视频国产永久2021_国产AV综合第一页一个的一区免费影院黑人_最近中文字幕MV高清在线视频

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

通過paho-mqtt軟件包入門rt-thread的sal

冬至子 ? 來源:happycode999 ? 作者:happycode999 ? 2023-08-09 15:37 ? 次閱讀

一、paho-mqtt軟件包程序流程

1.1 paho_mqtt_start
在rt_wlan_register_event_handler函數注冊好RT_WLAN_EVT_READY的回調函數paho_mqtt_start,當wifi準備好后調用mq_start啟動mqtt。在mq_start中,初始化MQTTClient結構體,設置mqtt連接的參數:mqtt的uri、mqtt的用戶名(username)和密碼(password)、mqtt發布和訂閱的主題Topic、消息質量等級QoS,最后調用paho_mqtt_start創建處理mqtt的線程paho_mqtt_thread。

static void mq_start(void)
{
/* init condata param by using MQTTPacket_connectData_initializer /
MQTTPacket_connectData condata = MQTTPacket_connectData_initializer;
static char cid[20] = { 0 };
static int is_started = 0;
if (is_started)
{
return;
}
/
config MQTT context param /
{
client.isconnected = 0;
client.uri = MQTT_URI;
/
generate the random client ID /
rt_snprintf(cid, sizeof(cid), "rtthread%d", rt_tick_get());
/
config connect param /
memcpy(&client.condata, &condata, sizeof(condata));
client.condata.clientID.cstring = cid;
client.condata.keepAliveInterval = 60;
client.condata.cleansession = 1;
client.condata.username.cstring = MQTT_USERNAME;
client.condata.password.cstring = MQTT_PASSWORD;
/
config MQTT will param. /
client.condata.willFlag = 1;
client.condata.will.qos = 1;
client.condata.will.retained = 0;
client.condata.will.topicName.cstring = MQTT_PUBTOPIC;
client.condata.will.message.cstring = MQTT_WILLMSG;
/
malloc buffer. /
client.buf_size = client.readbuf_size = 1024;
client.buf = malloc(client.buf_size);
client.readbuf = malloc(client.readbuf_size);
if (!(client.buf && client.readbuf))
{
LOG_E("no memory for MQTT client buffer!");
goto _exit;
}
/
set event callback function /
client.connect_callback = mqtt_connect_callback;
client.online_callback = mqtt_online_callback;
client.offline_callback = mqtt_offline_callback;
/
set subscribe table and event callback /
client.messageHandlers[0].topicFilter = MQTT_SUBTOPIC;
client.messageHandlers[0].callback = mqtt_sub_callback;
client.messageHandlers[0].qos = QOS1;
/
set default subscribe event callback /
client.defaultMessageHandler = mqtt_sub_default_callback;
}
/
run mqtt client /
paho_mqtt_start(&client);
is_started = 1;
_exit:
return;
}
rt_wlan_register_event_handler(RT_WLAN_EVT_READY, (void (
)(int, struct rt_wlan_buff *, void *))mq_start, RT_NULL);

1.2 paho_mqtt_thread
在paho_mqtt_thread中調用paho-mqtt提供的接口rt-thread的sal的接口完成與mqtt服務器的交互,包括以下幾個方面:與服務器的連接、訂閱主題、向服務器發送心跳包、處理服務器發送下來的消息(CONNACK、PUBACK、SUBACK、PUBLISH、PUBREC、PUBCOMP、PINGRESP)、回環服務器通過topic發送下來的消息。

static void paho_mqtt_thread(void *param)
{
MQTTClient *c = (MQTTClient )param;
int i, rc, len;
int rc_t = 0;
c->pub_sock = socket(AF_INET, SOCK_DGRAM, 0);
if (c->pub_sock == -1)
{
debug_printf("create pub_sock error!n");
goto _mqtt_exit;
}
/
bind publish socket. */
{
struct sockaddr_in pub_server_addr;
c->pub_port = pub_port;
pub_port ++;
pub_server_addr.sin_family = AF_INET;
pub_server_addr.sin_port = htons((c->pub_port));
pub_server_addr.sin_addr.s_addr = INADDR_ANY;
memset(&(pub_server_addr.sin_zero), 0, sizeof(pub_server_addr.sin_zero));
rc = bind(c->pub_sock, (struct sockaddr *)&pub_server_addr, sizeof(struct sockaddr));
if (rc == -1)
{
debug_printf("pub_sock bind error!n");
goto _mqtt_exit;
}
}
_mqtt_start:
if (c->connect_callback)
{
c->connect_callback(c);
}
rc = net_connect(c);
if (rc != 0)
{
goto _mqtt_restart;
}
rc = MQTTConnect(c);
if (rc != 0)
{
goto _mqtt_restart;
}
for (i = 0; i < MAX_MESSAGE_HANDLERS; i++)
{
const char topic = c->messageHandlers[i].topicFilter;
if(topic == RT_NULL)
continue;
rc = MQTTSubscribe(c, topic, QOS2);
debug_printf("Subscribe #%d %s %s!n", i, topic, (rc < 0) ? ("fail") : ("OK"));
if (rc != 0)
{
goto _mqtt_disconnect;
}
}
if (c->online_callback)
{
c->online_callback(c);
}
c->tick_ping = rt_tick_get();
while (1)
{
int res;
rt_tick_t tick_now;
fd_set readset;
struct timeval timeout;
tick_now = rt_tick_get();
if (((tick_now - c->tick_ping) / RT_TICK_PER_SECOND) > (c->keepAliveInterval - 5))
{
timeout.tv_sec = 1;
//debug_printf("tick close to ping.n");
}
else
{
timeout.tv_sec = c->keepAliveInterval - 10 - (tick_now - c->tick_ping) / RT_TICK_PER_SECOND;
//debug_printf("timeount for ping: %dn", timeout.tv_sec);
}
timeout.tv_usec = 0;
FD_ZERO(&readset);
FD_SET(c->sock, &readset);
FD_SET(c->pub_sock, &readset);
/
int select(maxfdp1, readset, writeset, exceptset, timeout); /
res = select(((c->pub_sock > c->sock) ? c->pub_sock : c->sock) + 1,
&readset, RT_NULL, RT_NULL, &timeout);
if (res == 0)
{
len = MQTTSerialize_pingreq(c->buf, c->buf_size);
rc = sendPacket(c, len);
if (rc != 0)
{
debug_printf("[%d] send ping rc: %d n", rt_tick_get(), rc);
goto _mqtt_disconnect;
}
/
wait Ping Response. /
timeout.tv_sec = 5;
timeout.tv_usec = 0;
FD_ZERO(&readset);
FD_SET(c->sock, &readset);
res = select(c->sock + 1, &readset, RT_NULL, RT_NULL, &timeout);
if (res <= 0)
{
debug_printf("[%d] wait Ping Response res: %dn", rt_tick_get(), res);
goto _mqtt_disconnect;
}
} /
res == 0: timeount for ping. */
if (res < 0)
{
debug_printf("select res: %dn", res);
goto _mqtt_disconnect;
}
if (FD_ISSET(c->sock, &readset))
{
//debug_printf("sock FD_ISSETn");
rc_t = MQTT_cycle(c);
//debug_printf("sock FD_ISSET rc_t : %dn", rc_t);
if (rc_t < 0) goto _mqtt_disconnect;
continue;
}
if (FD_ISSET(c->pub_sock, &readset))
{
struct sockaddr_in pub_client_addr;
uint32_t addr_len = sizeof(struct sockaddr);
MQTTMessage *message;
MQTTString topic = MQTTString_initializer;
//debug_printf("pub_sock FD_ISSETn");
len = recvfrom(c->pub_sock, c->readbuf, c->readbuf_size, MSG_DONTWAIT,
(struct sockaddr *)&pub_client_addr, &addr_len);
if (pub_client_addr.sin_addr.s_addr != *((uint32_t )(&netif_default->ip_addr)))
{
#if 1
char client_ip_str[16]; /
###.###.###.### */
strcpy(client_ip_str,
inet_ntoa(*((struct in_addr *) & (pub_client_addr.sin_addr))));
debug_printf("pub_sock recvfrom len: %s, skip!n", client_ip_str);
#endif
continue;
}
if (len < sizeof(MQTTMessage))
{
c->readbuf[len] = '?';
debug_printf("pub_sock recv %d byte: %sn", len, c->readbuf);
if (strcmp((const char *)c->readbuf, "DISCONNECT") == 0)
{
debug_printf("DISCONNECTn");
goto _mqtt_disconnect_exit;
}
continue;
}
message = (MQTTMessage *)c->readbuf;
message->payload = c->readbuf + sizeof(MQTTMessage);
topic.cstring = (char *)c->readbuf + sizeof(MQTTMessage) + message->payloadlen;
//debug_printf("pub_sock topic:%s, payloadlen:%dn", topic.cstring, message->payloadlen);
len = MQTTSerialize_publish(c->buf, c->buf_size, 0, message->qos, message->retained, message->id,
topic, (unsigned char *)message->payload, message->payloadlen);
if (len <= 0)
{
debug_printf("MQTTSerialize_publish len: %dn", len);
goto _mqtt_disconnect;
}
if ((rc = sendPacket(c, len)) != PAHO_SUCCESS) // send the subscribe packet
{
debug_printf("MQTTSerialize_publish sendPacket rc: %dn", rc);
goto _mqtt_disconnect;
}
} /* pbulish sock handler. */
} /* while (1) */
_mqtt_disconnect:
MQTTDisconnect(c);
_mqtt_restart:
if (c->offline_callback)
{
c->offline_callback(c);
}
net_disconnect(c);
rt_thread_delay(RT_TICK_PER_SECOND * 5);
debug_printf("restart!n");
goto _mqtt_start;
_mqtt_disconnect_exit:
MQTTDisconnect(c);
net_disconnect(c);
_mqtt_exit:
debug_printf("thread exitn");
return;
}

二、與mqtt broker的交互
paho-mqtt軟件包提供了兩種發布消息到mqtt broker的方式:udp和管道。在MQTTClient結構體中有三個成員與通信有關:sock、pub_sock、pub_pipe,其中sock是與mqtt broker通信的套接字,pub_sock和pub_pipe是兩種不同的發布方式:pub_sock是通過udp的方式發布消息;pub_pipe是通過管道,最終由sock發布消息。如下面的代碼所示,使用哪種方式可以通過宏來配置。下面展開描述這兩種方式如何與mqtt broker交互的。

/* publish interface */

#if defined(RT_USING_POSIX) && (defined(RT_USING_DFS_NET) || defined(SAL_USING_POSIX))
int pub_pipe[2];
#else
int pub_sock;
int pub_port;
#endif

2.1 管道(pipe)方式
在paho_mqtt_pipe.c中的paho_mqtt_thread,下面的代碼完成了發布消息、接收訂閱消息、處理心跳包的工作。下面以三個點細說。

當需要發布消息時,應用層需要調用MQTTPublish,這個函數會調用write向管道的寫端pub_pipe[1]寫入待發送的數據。而管道的讀端pub_pipe[0]在select中被監聽,當MQTTPublish被調用時,select可以往下執行,首先調用read從管道中讀取數據,接著調用MQTTSerialize_publish將數據封包,最后調用sendPacket將數據發送出去。

當接收到訂閱的消息時,select會往下執行,接著調用MQTT_cycle讀取并解析出數據。
select的超時時間是50s,如果50s沒有消息處理,則向broker發送心跳包。

FD_ZERO(&readset);
FD_SET(c->sock, &readset);
FD_SET(c->pub_pipe[0], &readset);
/* int select(maxfdp1, readset, writeset, exceptset, timeout); /
res = select(((c->pub_pipe[0] > c->sock) ? c->pub_pipe[0] : c->sock) + 1,
&readset, RT_NULL, RT_NULL, &timeout);
if (res == 0)
{
len = MQTTSerialize_pingreq(c->buf, c->buf_size);
rc = sendPacket(c, len);
if (rc != 0)
{
LOG_E("[%d] send ping rc: %d ", rt_tick_get(), rc);
goto _mqtt_disconnect;
}
/
wait Ping Response. /
timeout.tv_sec = 5;
timeout.tv_usec = 0;
FD_ZERO(&readset);
FD_SET(c->sock, &readset);
res = select(c->sock + 1, &readset, RT_NULL, RT_NULL, &timeout);
if (res <= 0)
{
LOG_E("[%d] wait Ping Response res: %d", rt_tick_get(), res);
goto _mqtt_disconnect;
}
} /
res == 0: timeount for ping. */
if (res < 0)
{
LOG_E("select res: %d", res);
goto _mqtt_disconnect;
}
if (FD_ISSET(c->sock, &readset))
{
//LOG_D("sock FD_ISSET");
rc_t = MQTT_cycle(c);
//LOG_D("sock FD_ISSET rc_t : %d", rc_t);
if (rc_t < 0) goto _mqtt_disconnect;
continue;
}
if (FD_ISSET(c->pub_pipe[0], &readset))
{
MQTTMessage *message;
MQTTString topic = MQTTString_initializer;
//LOG_D("pub_sock FD_ISSET");
len = read(c->pub_pipe[0], c->readbuf, c->readbuf_size);
if (len < sizeof(MQTTMessage))
{
c->readbuf[len] = '?';
LOG_D("pub_sock recv %d byte: %s", len, c->readbuf);
if (strcmp((const char *)c->readbuf, "DISCONNECT") == 0)
{
LOG_D("DISCONNECT");
goto _mqtt_disconnect_exit;
}
continue;
}
message = (MQTTMessage *)c->readbuf;
message->payload = c->readbuf + sizeof(MQTTMessage);
topic.cstring = (char *)c->readbuf + sizeof(MQTTMessage) + message->payloadlen;
//LOG_D("pub_sock topic:%s, payloadlen:%d", topic.cstring, message->payloadlen);
len = MQTTSerialize_publish(c->buf, c->buf_size, 0, message->qos, message->retained, message->id,
topic, (unsigned char *)message->payload, message->payloadlen);
if (len <= 0)
{
LOG_D("MQTTSerialize_publish len: %d", len);
goto _mqtt_disconnect;
}
if ((rc = sendPacket(c, len)) != PAHO_SUCCESS) // send the subscribe packet
{
LOG_D("MQTTSerialize_publish sendPacket rc: %d", rc);
goto _mqtt_disconnect;
}
}

2.2 udp方式
udp方式中,處理流程與管道方式基本相似。下面說明一下這種方式兩個套接字的工作流程。
MQTTClient結構體中有兩個socket,一個是基于tcp的負責控制與服務器連接的sock,另一個是基于udp協議的負責消息發布的pub_sock。

2.2.1 sock
連接:在net_connect調用socket、connet函數建立與服務器的tcp連接。
處理:sock接收到服務器的數據后,在MQTT_cycle中處理來自服務器的CONNACK、PUBACK、SUBACK、PUBLISH、PUBREC、PUBCOMP、PINGRESP消息。
斷開連接:在net_disconnect函數中調用closesocket關閉與服務器的tcp連接。

2.2.2 pub_sock
連接:分為pub_sock的綁定和mqtt連接的建立
1、調用socket創建pub_sock,之后調用bind綁定pub_sock到udp端口
2、在MQTTConnect函數中,通過sock發送connect消息給服務器,建立mqtt連接。
處理:先recvfrom將接受的數據拷貝到MQTTClient的readbuf,再將數據回環發布到服務器。
斷開連接:通過sock向服務器發送DISCONNECT消息,斷開mqtt連接。

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 處理器
    +關注

    關注

    68

    文章

    19177

    瀏覽量

    229195
  • WLAN技術
    +關注

    關注

    0

    文章

    23

    瀏覽量

    9271
  • RT-Thread
    +關注

    關注

    31

    文章

    1274

    瀏覽量

    39938
  • MQTT
    +關注

    關注

    5

    文章

    649

    瀏覽量

    22439
  • MQTT協議
    +關注

    關注

    0

    文章

    97

    瀏覽量

    5351
  • TCP通信
    +關注

    關注

    0

    文章

    146

    瀏覽量

    4217
收藏 人收藏

    評論

    相關推薦

    RT-Thread記錄(十八、SHT21與24C02軟件包

    本文學習測試一下幾款典型設備的 RT-Thread I2C軟件包
    的頭像 發表于 07-08 11:07 ?3330次閱讀
    <b class='flag-5'>RT-Thread</b>記錄(十八、SHT21與24C02<b class='flag-5'>軟件包</b>)

    如何利用RT-Thread開發的PahoMQTT軟件包MQTT服務器進行通信?

    本教程就是介紹如何利用 RT-Thread 開發的 Paho MQTT 軟件包MQTT 服務器進行通信的。
    發表于 03-30 08:09

    介紹RT-Thread軟件包

    學習要點介紹 RT-Thread軟件包;簡介 nRF24L01 軟件包的使用,講解如何使用此軟件包將數據正確發送和接收;學習線程間的通信,IPC 的使用,即獲取溫度的線程 A 與無
    發表于 07-27 06:07

    WIZnet軟件包對接RT-Thread SAL套接字抽象層實現對BSD Socket APIs的支持

    RT-Thread SAL 套接字抽象層,實現對標準 BSD Socket APIs 的支持,完美的兼容多種軟件包和網絡功能實現,提高 WIZnet 設備兼容性。1.1 目錄結構WIZnet
    發表于 05-17 17:00

    使用menuconfig配置基于RT-Thread的NimBLE軟件包

    最近在學習 RT-Thread 中的 NimBLE 軟件包,使用 menuconfig 配置選中 NimBLE 軟件包,設置各種選項后,成功通過編譯并且運行起來。不過這僅僅只是按照文檔
    發表于 06-27 11:18

    UIoT RT-Thread軟件包介紹

    UIoT RT-Thread 軟件包實現了 IoT 設備與 UCloud UIoT Core 物聯網通信云平臺連接,包含設備注冊、MQTT、設備影子、物模型、OTA、文件上傳等功能,開發者進行靈活裁剪。
    發表于 09-26 07:22

    RT-Thread 軟件包介紹

    軟件包的使用RT-Thread 為開發者提供的全面的使用教程,詳情如下:入門文檔教程:位于 RT-Thread 官網,文檔->開發指南->env 工具用戶手冊
    發表于 05-21 19:38 ?5537次閱讀

    RT-Thread軟件包定義和使用

    RT-Thread軟件包是運行于RT-Thread物聯網操作系統平臺上,面向不同應用領域的通用軟件組件 。RT-Thread 同時提供了開放
    的頭像 發表于 05-21 11:29 ?1w次閱讀
    <b class='flag-5'>RT-Thread</b><b class='flag-5'>軟件包</b>定義和使用

    RT-Thread社區上有哪些優秀的軟件包

    SX12XX 軟件包是基于 semtech 官網 Firmware Drivers V2.1.0代碼庫的移植實現,目前只支持 SX1278 LoRa設備。該軟件包在原代碼庫功能的基礎上,對接 RT-Thread SPI 設備驅動
    的頭像 發表于 04-03 15:35 ?7602次閱讀

    2022 RT-Thread全球技術大會:RT-Thread軟件包

    RT-Thread在2022年上半年新增幾十個軟件包:rtt-rust、LuatOS、gui-guider-demo。
    的頭像 發表于 05-27 14:12 ?1033次閱讀
    2022 <b class='flag-5'>RT-Thread</b>全球技術大會:<b class='flag-5'>RT-Thread</b><b class='flag-5'>軟件包</b>

    RT-Thread全球技術大會:恩智浦新增100+軟件包

    RT-Thread全球技術大會:恩智浦新增100+軟件包,支持了很多有用的功能。 ? ? ? ? ? ? 審核編輯:彭靜
    的頭像 發表于 05-27 14:26 ?936次閱讀
    <b class='flag-5'>RT-Thread</b>全球技術大會:恩智浦新增100+<b class='flag-5'>軟件包</b>

    RT-Thread在線軟件包改為本地軟件包的方法

    RT-Thread軟件包,使用時需要手動通過 ENV 工具 更新到 本地的 packages 目錄,并且 packages 目錄默認不參與 Git 工程管理,軟件包多了,偶爾需要更
    的頭像 發表于 08-11 15:02 ?1149次閱讀
    <b class='flag-5'>RT-Thread</b>在線<b class='flag-5'>軟件包</b>改為本地<b class='flag-5'>軟件包</b>的方法

    RT-Thread使用cjson軟件包發送64位長整型數據

    開發環境:野火的stm32f407,rt-thread studio版本是版本: 2.2.6,stm32f4的資源為0.2.2,rt-thread版本為4.1.1,cjson軟件包使
    的頭像 發表于 10-11 15:09 ?879次閱讀
    <b class='flag-5'>RT-Thread</b>使用cjson<b class='flag-5'>軟件包</b>發送64位長整型數據

    RT-Thread中Agile Modbus軟件包的使用方法

    開發環境:野火的stm32f407,rt-thread studio版本是版本: 2.2.6,stm32f4的資源為0.2.2,Agile Modbus軟件包版本為v1.1.2。工程使用上一篇
    的頭像 發表于 10-11 15:37 ?2448次閱讀
    <b class='flag-5'>RT-Thread</b>中Agile Modbus<b class='flag-5'>軟件包</b>的使用方法

    RT-Thread中mymqtt軟件包的使用方法

    在上一篇文章 RT-Thread中Lan8720和lwip協議棧的使用的工程基礎上添加mymqtt軟件包。 使能mqtt example和mqtt test,保存,等待下載更新
    的頭像 發表于 10-13 10:44 ?930次閱讀
    <b class='flag-5'>RT-Thread</b>中mymqtt<b class='flag-5'>軟件包</b>的使用方法