Paho MQTT 嵌入式c客户端研究笔记 (二)

AI权益加码!Claude Code、Cursor等20+工具免费用! 购周边限时加赠Coding Plan Lite,畅享主流AI工具!学习进阶更高效! 阅读详情

  paho.mqtt.embedded-c-master\MQTTPacket\samples,这个目录里面封装了发布消息、订阅消息的示例。运行pub0sub1,这个示例里面会去订阅主题消息、发布主题消息。并且订阅和发布的消息是同一个主题,所以在运行过程中会看到循环打印同一份消息。代码如下:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include "MQTTPacket.h"
#include "transport.h"

/* This is in order to get an asynchronous signal to stop the sample,
as the code loops waiting for msgs on the subscribed topic.
Your actual code will depend on your hw and approach*/
#include <signal.h>

int toStop = 0;

void cfinish(int sig)
{
    signal(SIGINT, NULL);
    toStop = 1;
}

void stop_init(void)
{
    signal(SIGINT, cfinish);
    signal(SIGTERM, cfinish);
}
/* */

int main(int argc, char *argv[])
{
    MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
    int rc = 0;
    int mysock = 0;
    unsigned char buf[200];
    int buflen = sizeof(buf);
    int msgid = 1;
    MQTTString topicString = MQTTString_initializer;
    int req_qos = 0;
    char* payload = "mypayload";
    int payloadlen = strlen(payload);
    int len = 0;
    char *host = "m2m.eclipse.org";
    int port = 1883;

    stop_init();
    if (argc > 1)
        host = argv[1];

    if (argc > 2)
        port = atoi(argv[2]);

    mysock = transport_open(host, port);
    if(mysock < 0)
        return mysock;

    printf("Sending to hostname %s port %d\n", host, port);

    data.clientID.cstring = "me";
    data.keepAliveInterval = 20;
    data.cleansession = 1;
    data.username.cstring = "testuser";
    data.password.cstring = "testpassword";
    //连接服务器
    len = MQTTSerialize_connect(buf, buflen, &data);
    rc = transport_sendPacketBuffer(mysock, buf, len);

    /* wait for connack */
    if (MQTTPacket_read(buf, buflen, transport_getdata) == CONNACK)
    {
        unsigned char sessionPresent, connack_rc;

        if (MQTTDeserialize_connack(&sessionPresent, &connack_rc, buf, buflen) != 1 || connack_rc != 0)
        {
            printf("Unable to connect, return code %d\n", connack_rc);
            goto exit;
        }
    }
    else
        goto exit;

    /* subscribe 订阅主题消息*/
    topicString.cstring = "substopic";
    len = MQTTSerialize_subscribe(buf, buflen, 0, msgid, 1, &topicString, &req_qos);

    rc = transport_sendPacketBuffer(mysock, buf, len);
    if (MQTTPacket_read(buf, buflen, transport_getdata) == SUBACK)  /* wait for suback */
    {
        unsigned short submsgid;
        int subcount;
        int granted_qos;        
        rc = MQTTDeserialize_suback(&submsgid, 1, &subcount, &granted_qos, buf, buflen);
        if (granted_qos != 0)
        {
            printf("granted qos != 0, %d\n", granted_qos);
            goto exit;
        }
    }
    else
        goto exit;

    /* loop getting msgs on subscribed topic循环读取消息 */
    topicString.cstring = "pubtopic";
    while (!toStop)
    {
        /* transport_getdata() has a built-in 1 second timeout,
        your mileage will vary */
        if (MQTTPacket_read(buf, buflen, transport_getdata) == PUBLISH)
        {
            unsigned char dup;
            int qos;
            unsigned char retained;
            unsigned short msgid;
            int payloadlen_in;
            unsigned char* payload_in;
            int rc;
            MQTTString receivedTopic;

            rc = MQTTDeserialize_publish(&dup, &qos, &retained, &msgid, &receivedTopic,
                    &payload_in, &payloadlen_in, buf, buflen);
            printf("message arrived %.*s\n", payloadlen_in, payload_in);
        }

        printf("publishing reading\n");
        //下面两行是用来发布消息。这里发布,上面订阅,就形成了一个循环。
        len = MQTTSerialize_publish(buf, buflen, 0, 0, 0, 0, topicString, (unsigned char*)payload, payloadlen);
        rc = transport_sendPacketBuffer(mysock, buf, len);
    }

    printf("disconnecting\n");
    len = MQTTSerialize_disconnect(buf, buflen);
    rc = transport_sendPacketBuffer(mysock, buf, len);

exit:
    transport_close(mysock);

    return 0;
}

在这个示例中,改造一下,把发布消息的代码给注释掉。我们发现,过了一会,循环读消息的地方就再也接收不到服务器发送过来的消息了。推测是此时客户端与服务器之间的长连接已经断了。回到代码,

//设置心跳包间隔时间
data.keepAliveInterval = 20;

Keep Alive timer
The Keep Alive timer is present in the variable header of a MQTT CONNECT message.

The Keep Alive timer, measured in seconds, defines the maximum time interval between >messages received from a client. It enables the server to detect that the network connection to a client has dropped, without having to wait for the long TCP/IP timeout. The client has a responsibility to send a message within each Keep Alive time period. In the absence of a data-related message during the time period, the client sends a PINGREQ message, which the server acknowledges with a PINGRESP message.

If the server does not receive a message from the client within one and a half times the Keep Alive time period (the client is allowed “grace” of half a time period), it disconnects the client as if the client had sent a DISCONNECT message. This action does not impact any of the client’s subscriptions. See DISCONNECT for more details.

If a client does not receive a PINGRESP message within a Keep Alive time period after sending a PINGREQ, it should close the TCP/IP socket connection.

The Keep Alive timer is a 16-bit value that represents the number of seconds for the time period. The actual value is application-specific, but a typical value is a few minutes. The maximum value is approximately 18 hours. A value of zero (0) means the client is not disconnected.

The format of the Keep Alive timer is shown in the table below. The ordering of the 2 bytes of the Keep Alive Timer is MSB, then LSB (big-endian).

  pub0sub1示例代码中,删除发布消息代码块只保留订阅消息功能以后,客户端在20秒之内都可以接收到服务器推送过来的消息。如果20秒内客户端没有向服务器发送PINGREQ消息,那么服务器会关闭掉TCP/IP端口连接。
  因此,如果希望开启一个可以永远保持订阅消息的客户端,需要在设置的心跳间隔时间内向服务器发送PINGREQ消息。具体做法可以这样,代码如下:

while (!toStop)
    {

        /****循环订阅消息*************/
        topicString.cstring = "pubtopic";
        len = MQTTSerialize_subscribe(buf, buflen, 0, msgid, 1, &topicString, &req_qos);

        rc = transport_sendPacketBuffer(mysock, buf, len);
        printf("publishing reading000\n");
        if (MQTTPacket_read(buf, buflen, transport_getdata) == SUBACK)  /* wait for suback */
        {
            unsigned short submsgid;
            int subcount;
            int granted_qos;

            rc = MQTTDeserialize_suback(&submsgid, 1, &subcount, &granted_qos, buf, buflen);
            if (granted_qos != 0)
            {
                printf("granted qos != 0, %d\n", granted_qos);
                goto exit;
            }
        }
        else
            goto exit;
        /*****************/
        /* transport_getdata() has a built-in 1 second timeout,
        your mileage will vary */
        int state = MQTTPacket_read(buf, buflen, transport_getdata);
        //printf("state is = %d\n", state);
        //printf("PUBLISH is = %d\n", PUBLISH);
        if (state != -1){
                    printf("state2 is = %d\n", state);
            }
        if (state == PUBLISH)
        {
            unsigned char dup;
            int qos;
            unsigned char retained;
            unsigned short msgid;
            int payloadlen_in;
            unsigned char* payload_in;
            int rc;
            MQTTString receivedTopic;

            rc = MQTTDeserialize_publish(&dup, &qos, &retained, &msgid, &receivedTopic,
                    &payload_in, &payloadlen_in, buf, buflen);
            printf("message arrived %.*s\n", payloadlen_in, payload_in);            
        }

        //printf("publishing reading\n");
        //len = MQTTSerialize_publish(buf, buflen, 0, 0, 0, 0, topicString, (unsigned char*)payload, payloadlen);
        //rc = transport_sendPacketBuffer(mysock, buf, len);
    }

  我们在循环读取消息的代码块中加入了订阅消息,这样可以保持客户端与服务器之间长连接不会断开。当然,这么做效果并不好,因为循环发送订阅消息会对服务器产生比较多的负载。可以对代码做个优化,比如每间隔10秒钟发送一次订阅消息的请求。百度云官方提供的客户端代码就是这么实现的,下一次我们拿出来做对比。文档代码点这里

paho.mqtt.embedded-c 移植 阅读详情

相关推荐

【大厂必问】MQTT底层实现 | MQTT源码分析

同学面试大疆音视频驱动,问了很多Linux驱动细节和MQTT底层实现,被问麻了。我根据韦东山老师讲解MQTT笔记补充和拓展了很多实现代码。丰富了对MQTT网络协议的理解。

记录嵌入式技能成长的博客 5599

paho.mqtt.embedded-c-master.zip_MQTT编程_c mqtt linux_mqtt_paho mq

mqtt linux paho.mqtt.embedded-c-master.zip软件包

MQTTMQTT C语言客户端实现/ MQTT嵌入式客户端

MQTT客户端实现(嵌入式) 最新最容易使用的mqtt封装。 MQTT客户端实现(使用Eclipse Paho C库,进行了次封装)。 在Linkit7688单片机上运行测试通过,附例程。 https://download.csdn.net/download/skyformat99/9969954 MQTT 客户端C语言编好的库和例子(example) https://downlo...

我的笔记本 8311

paho.mqtt-sn.embedded-c:用于嵌入式系统的Paho C MQTT-SN网关和库。 Paho是一个Eclipse IoT项目

用于嵌入式平台的Eclipse Paho MQTT-SN C / C ++客户端 该存储库包含用于嵌入式平台的 MQTT-SN C / C ++客户端库的源代码。 它在EPL和EDL下获得了双重许可(有关更多详细信息,请参见about.html和notice.html)。 您可以选择要使用以下代码中的哪些许可证。 EDL允许您将代码嵌入到应用程序中,并以进制或源代码形式分发应用程序,而无需贡献任何代码或对Paho进行任何更改。 有关确切条件,请参阅EDL。 有三个子项目: MQTTSNPacket-MQTT-SN数据包的简单反序列化,以及辅助函数 MQTTGateway-MQTT-SN透明/聚合网关-MQTT-SN客户端MQTT服务器连接。 有关更多信息,请参见项目中的自述文件。 MQTTSNClient-高级C ++客户端(尚未完成) MQTTSNPacket目录包含具有

使用paho.mqtt.embedded-c和openssl实现MQTT的单向认证功能

使用paho.mqtt.embedded-c和openssl实现MQTT的单向认证功能

a287574014的博客 3013

用QT测试 paho.mqtt.embedded-c-master嵌入式MQTT开发

最近的项目需要在stm32中移植MQTT协议,为了在移植之前对这套针对嵌入式的C语言库有个了解,决定先用QT构建纯C程序移植测试。运行环境:WIN7 64位QT3.2.11、QT选择【非QT项目】-【纯C语言项目】创建 一个使用QMake的纯C语言项目,不使用QT库2、打开 paho.mqtt.embedded-c-master文件夹,再打开MQTTPacket文件夹,复制src文件夹到工程下面3...

tengjingmeicai的专栏 2065

一个高性能、高稳定性的跨平台MQTT客户端——mqttclient设计与实现方式

文章目录mqttclient设计与实现方式设计思想API接口MQTT客户端的核心结构mqttclient实现申请一个mqtt客户端释放已申请的mqtt客户端设置MQTT客户端的信息连接服务器订阅报文取消订阅发布报文内部线程核心的处理函数发布应答与发布完成报文的处理订阅应答报文的处理取消订阅应答报文的处理来自服务器的发布报文的处理发布收到与发布释放报文的处理 mqttclient设计与实现方式 设计思想 整体采用分层式设计,代码实现采用异步设计方式,降低耦合。 消息的处理使用回调的方式处理:用户指定订

杰杰的博客 7893

Paho mqtt C语言库介绍

虽然可以自己构造MQTT报文,但是还是比较麻烦的,采用别人设计好的库,速度更快,也不容易出现某些自己无法解决的bug,Paho基于C语言,Java,C++,,Python等主流编程语封装了MQTT的库,这次我们的参赛作品就使用了C++,Java,还有C语言Paho封装的mqtt库。非常的方便,下面是基于C语言实现的库的github下载地址。 下载地址:Paho https://github.com/eclipse/paho.mqtt.embedded-c Paho库目录文件介绍 解压...

a310171579的博客 1万+

MQTTpaho.mqtt.cpp 库的 介绍、下载、交叉编译、MQTT客户端例子源码

👉本文详细介绍了 paho.mqtt.cpp 库的“下载、交叉编译”、最后给出了怎么写MQTT客户端例子源码的例子

wkd_007的博客 1万+

MQTTpaho.mqtt.c 库的“介绍、下载、交叉编译” 详解,以及编写MQTT客户端例子源码

👉本文详细介绍了 paho.mqtt.c 库的“介绍、下载、交叉编译” ,以及怎么使用 aho.mqtt.c 库 编写MQTT客户端例子源码。

wkd_007的博客 9620

C语言基于paho实现MQTT客户端实战案例

C语言基于paho实现MQTT客户端实战案例

qqq1112345的博客 7140

paho.mqtt.embedded-c-1.0.0

# Eclipse Paho MQTT C/C++ client for Embedded platforms This repository contains the source code for the [Eclipse Paho](http://eclipse.org/paho) MQTT C/C++ client library for Embedded platorms.

MQTT】基于Paho C库的嵌入式MQTT客户端开发实战指南

本文是一份针对嵌入式开发的MQTT客户端实战指南,详细介绍了如何基于轻量级的Paho C库进行开发。内容涵盖从源码获取、工程搭建、核心网络层移植,到客户端初始化、消息收发、稳定性保障及性能调优的全过程,旨在帮助开发者在资源受限的嵌入式设备上实现稳定高效的MQTT通信。

yy01234的博客 894

C++的MQTT开发:使用Paho的C++接口实现消息发布、订阅、连接RabbitMQ

具体的MQTT应用程序可能会有不同的需求和限制。如果应用程序需要在发送消息之间有较长的时间间隔,或者需要处理长时间的非活动状态,那么可以考虑在一段时间后断开连接,并在需要时重新连接。您可以参考paho的官方文档和示例代码来进一步了解和掌握paho的cpp接口的使用。本示例代码仅提供了一个基本的框架,需要根据自己的需求进行更多的自定义和错误处理。是异步的客户端实现,它使用了异步操作和回调函数来处理发送和接收消息,不会阻塞当前线程。提供了更强大的功能和更好的并发性能,但它需要更多的代码和处理异步回调函数。

BigBookX's Blog 9585

paho.mqtt.embedded-c:嵌入式平台上的高效MQTT客户端

在物联网(IoT)技术迅猛发展的当下,消息队列遥测传输(MQTT)协议因其轻量级、低功耗的特点,成为了连接各种设备与系统的首选。paho.mqtt.embedded-c 是一个为嵌入式平台设计的开源 MQTT C/C++ 客户端库。该项目由 Eclipse Paho 社区维护,旨在提供一种简单、高效的方式来接入 MQTT 服务。 ## 项目技术分析 paho.mqtt.embedded-c 采...

gitblog_01033的博客 1039

[嵌入式开发模块]MQTT开源库Paho嵌入式C/C++版本的移植及使用(基于W5500 io库)

这篇文章讲解了PahoMQTT嵌入式C库的移植及使用。实现在嵌入式系统上实现MQTT client。

夏日白云的boke 1万+

交叉编译OpenSSL和paho.mqtt.c

交叉编译OpenSSL和paho.mqtt.c

onlyshi的专栏 4919

交叉编译paho.mqtt.c和paho.mqtt.cpp(MQTT客户端

交叉编译paho.mqtt.c和paho.mqtt.cpp(MQTT客户端

IT菜鸟 1787

Paho MQTT 嵌入式c客户端研究笔记

最近做物联网设备,需求长连接推送功能。当前物联网有一个标准协议是MQTT,对应有很多开源服务端,如何快速接入这个服务呢。有两种接入方案:   1.自己clone 代码修改维护。   2.找第三方服务,比如当前提供支持的有云巴,bat。bat目前都还处于公测中,at使用都需要申请设备,b可以直接接入。对比了价格,b最便宜,一个月免费消息1百万条。   最后决定先尝试使用百度云的MQTT服务后台,

读书未遍、未敢妄下雌黄 1万+
上一篇: Paho MQTT 嵌入式c客户端研究笔记
下一篇: Android图片系列-2.Android App图片压缩、裁剪分析整理
rocky-bull
博客等级 码龄17年 70粉丝 79原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值