热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Linux下学习用C语言实现MQTT(一)(同步函数)

Linux下学习用C语言实现MQTT(一)(同步函数),Go语言社区,Golang程序员人脉社

使用系统版本Ubuntu14.04(该文章代码严谨性并不高,主要用于了解MQTT)
先介绍一下MQTT:
MQTT(Message Queuing Telemetry Transport,消息队列遥测传输)是IBM开发的一个即时通讯协议,有可能成为物联网的重要组成部分。该协议支持所有平台,几乎可以把所有联网物品和外部连接起来,被用来当做传感器和制动器(比如通过Twitter让房屋联网)的通信协议。
MQTT协议是为大量计算能力有限,且工作在低带宽、不可靠的网络的远程传感器和控制设备通讯而设计的协议,它具有以下主要的几项特性:

1、使用发布/订阅消息模式,提供一对多的消息发布,解除应用程序耦合;

2、对负载内容屏蔽的消息传输;

3、使用 TCP/IP 提供网络连接;

4、有三种消息发布服务质量:

“至多一次”,消息发布完全依赖底层 TCP/IP 网络。会发生消息丢失或重复。这一级别可用于如下情况,环境传感器数据,丢失一次读记录无所谓,因为不久后还会有第二次发送。

“至少一次”,确保消息到达,但消息重复可能会发生。

“只有一次”,确保消息到达一次。这一级别可用于如下情况,在计费系统中,消息重复或丢失会导致不正确的结果。

5、小型传输,开销很小(固定长度的头部是 2 字节),协议交换最小化,以降低网络流量;

6、使用 Last Will 和 Testament 特性通知有关各方客户端异常中断的机制;

在这里插入图片描述

使用客户端库的应用程序通常使用类似的结构:
  1.创建一个客户端对象;
  2.设置连接MQTT服务器的选项;
  3.如果多线程(异步模式)操作被使用则设置回调函数(详见 Asynchronous vs synchronous client applications);
  4.订阅客户端需要接收的任意话题;
  5.重复以下操作直到结束:
    a.发布客户端需要的任意信息;
    b.处理所有接收到的信息;
  6.断开客户端连接;
  7.释放客户端使用的所有内存。

接下来开始谈LinuxC编程简单实现MQTT
在linux下用C语言实现MQTT通信,要用到一系列MQTT函数,这些函数在Linux自带库中是没有的。
所以第一步:安装Paho C库
在git下下载paho C库git clone https://github.com/eclipse/paho.mqtt.c.git

cd paho.mqtt.c
make//编译
sudo make install//安装

在编译时可能出现某些头文件的缺失,这里我就不一一列举了,问百度把哈哈哈

在执行make之后,在build/output下能看到这些动态库,这些库中有我们将要用到的函数的定义

zhanghang@Ubuntu-14:~/MQTT/paho.mqtt.c/build/output$ ls
libpaho-mqtt3a.so      libpaho-mqtt3as.so      libpaho-mqtt3c.so      libpaho-mqtt3cs.so      paho_c_version
libpaho-mqtt3a.so.1    libpaho-mqtt3as.so.1    libpaho-mqtt3c.so.1    libpaho-mqtt3cs.so.1    samples
libpaho-mqtt3a.so.1.0  libpaho-mqtt3as.so.1.0  libpaho-mqtt3c.so.1.0  libpaho-mqtt3cs.so.1.0  test

在这里说一下这里面的各个动态库的作用:
paho-mqtt3a : 一般实际开发中就是使用这个,a表示的是异步消息推送(asynchronous)。
paho-mqtt3as : as表示的是 异步+加密(asynchronous+OpenSSL)。
paho-mqtt3c : c 表示的应该是同步(Synchronize),一般性能较差,是发送+等待模式。
paho-mqtt3cs : 同上,增加了一个OpenSSL而已。
在samples中还会有一些示例代码;

zhanghang@Ubuntu-14:~/MQTT/paho.mqtt.c/build/output/samples$ ls
MQTTAsync_publish    MQTTClient_publish        MQTTClient_subscribe  paho_cs_pub  paho_c_sub
MQTTAsync_subscribe  MQTTClient_publish_async  paho_c_pub            paho_cs_sub

现在给发布端的C代码:

#include
#include
#include
#include
#include
#include"MQTTClient.h"

int main(int argc,char **argv)
{
    char *address="tcp://localhost:1883";
    char *client_id="publish_client";
    char *topic="mqtt_examples";
    char buf[1024];
    const int time_out=10000;
    int  rv;
    int  QOS=1;
    MQTTClient   client;
    MQTTClient_connectOptions conn_opts=MQTTClient_connectOptions_initializer;
    MQTTClient_message publish_msg=MQTTClient_message_initializer;
    MQTTClient_deliveryToken token;

    conn_opts.keepAliveInterval=60;
    conn_opts.cleansession=1;

    MQTTClient_create(&client,address,client_id,MQTTCLIENT_PERSISTENCE_NONE,NULL);
    if((rv=MQTTClient_connect(client,&conn_opts))!=MQTTCLIENT_SUCCESS)
    {
    printf("MQTTClient_connect failure:%sn",strerror(errno));
        return 0;
    }
    publish_msg.qos=QOS;
    publish_msg.retained=0;
    while(1)
    {
        printf("enter the message you want to sendn");
        fgets(buf,sizeof(buf),stdin);
        publish_msg.payload=(void *)buf;
        publish_msg.payloadlen=strlen(buf);
        MQTTClient_publishMessage(client,topic,&publish_msg,&token);
        printf("waiting for %d seconds for publication of %s on topic %s for client with CLIENTID :%sn",time_out/1000,buf,topic,client_id);
        rv=MQTTClient_waitForCompletion(client,token,time_out);
        printf("Message with delivery token %d deliveredn",rv);
        printf("%sn",buf);//用于测试
        sleep(3);
    }
}

注意编译时,如果没将相应的头文件和动态库放到编译器默认寻找的位置需要加上相应的链接选项,如下:

zhanghang@Ubuntu-14:~$ gcc mqtt_publish.c -o mqtt_publish -lpaho-mqtt3c -L ./MQTT/paho.mqtt.c/ -I ./MQTT/paho.mqtt.c/src/

运行如下

zhanghang@Ubuntu-14:~$ ./mqtt_publish 
enter the message you want to send

采用交互式传递类似网络soket的传递信息,便于理解

下面给出一个简单的订阅端程序:

#include
#include
#include
#include
#include
#include"MQTTClient.h"

int main()
{
    char *address="tcp://localhost:1883";
    char *client_id="client_sub";
    char *payload="mqtt_examples";
    int    rv,i;
    char *ptr=NULL;
    char *topic=NULL;
    int topic_len;
    MQTTClient client;
    MQTTClient_connectOptions conn_opts=MQTTClient_connectOptions_initializer;
    MQTTClient_deliveryToken token;
    MQTTClient_message *receive_msg=NULL;
    conn_opts.keepAliveInterval=60;
    conn_opts.cleansession=1;

    if((rv=MQTTClient_create(&client,address,client_id,MQTTCLIENT_PERSISTENCE_NONE,NULL))<0)
    {
        printf("MQTTClient_create failure:%sn",strerror(errno));
        return 0;
    }
    printf("MQTTClient_create successfullyn");
    if((rv=MQTTClient_connect(client,&conn_opts))!=MQTTCLIENT_SUCCESS)
    {
        printf("MQTTClient_connect failure:%sn",strerror(errno));
        return 0;
    }
    printf("MQTTClient_connect successfulyn");
    MQTTClient_subscribe(client,payload,1);
    /* if((rv=MQTTClient_receive(client,&topic,&topic_len,&receive_msg,5000))!=MQTTCLIENT_SUCCESS)
    { 
        printf("MQTTClient_receive failure:%sn",strerror(errno));
        return 0;
    }  
    printf("MQTTClient_receive successfullyn");*/
    //receive 函数放在外面传递信息不会改变
    while(1)
    {
        if((rv=MQTTClient_receive(client,&topic,&topic_len,&receive_msg,100000))!=MQTTCLIENT_SUCCESS)//最后一个参数是超时时间,单位是毫秒
        {
            printf("MQTTClient_receive failure:%sn",strerror(errno));
            break;
        }
        printf("MQTTClient_receive successfullyn");
        ptr=receive_msg->payload;
        printf("Topic:%snTopic_len:%dnmsg:",topic,topic_len);
        for(i=0;i<receive_msg->payloadlen;i++)
        {
            putchar(*ptr++);
        }
        printf("nmsg_len:%dnmsg_id:%dn",receive_msg->payloadlen,receive_msg->msgid);
        sleep(3);
    }
    printf("endn");
    MQTTClient_disconnect(client, 10000);
    MQTTClient_destroy(&client);
    return 0;
}

订阅端订阅了话题mqtt_examples,同样采用循环不断接受消息;
编译:

zhanghang@Ubuntu-14:~$ gcc mqtt_subscribe.c -o mqtt_subscribe -lpaho-mqtt3c -L ./MQTT/paho.mqtt.c/build/output/

**注意:在运行时也有可能出现找不到动态库,因为编译是默认动态编译,在运行时才会加载动态库
解决办法:假设需要的库在/test/lib下则可以:

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/test/lib      //该方法重启会失效

如果有sudo去权限也可以将这句话加到~/.bashrc中,重启生效**

此时我们分别在两个终端运行publish和subsceibe:

zhanghang@Ubuntu-14:~$ ./mqtt_publish 
enter the message you want to send
zhanghang@Ubuntu-14:~$ ./mqtt_subscribe 
MQTTClient_create successfully
MQTTClient_connect successfuly

在publish端发送信息,可在subscrib端收到信息:

zhanghang@Ubuntu-14:~$ ./mqtt_publish 
enter the message you want to send
hello
waiting for 10 seconds for publication of hello
 on topic mqtt_examples for client with CLIENTID :publish_client
Message with delivery token 0 delivered
hello

hienter the message you want to send

waiting for 10 seconds for publication of hi
 on topic mqtt_examples for client with CLIENTID :publish_client
Message with delivery token 0 delivered
hi

enter the message you want to send
it is me
waiting for 10 seconds for publication of it is me
 on topic mqtt_examples for client with CLIENTID :publish_client
Message with delivery token 0 delivered
it is me

enter the message you want to send
zhanghang@Ubuntu-14:~$ ./mqtt_subscribe 
MQTTClient_create successfully
MQTTClient_connect successfuly
MQTTClient_receive successfully
Topic:mqtt_examples
Topic_len:13
msg:hello

msg_len:6
msg_id:1
MQTTClient_receive successfully
Topic:mqtt_examples
Topic_len:13
msg:hi

msg_len:3
msg_id:2
MQTTClient_receive successfully
Topic:mqtt_examples
Topic_len:13
msg:it is me

msg_len:9
msg_id:3

使用mosquitto和mqtt.fx软件测试无论是publish还是subscribe都能通过
下一节详细讲解里面用到的一些函数。
(在此处学习过程中遇到过一些问题:在安装paho-mqtt.c后,编译时可能会出现头文件缺失等问题,这种问题百度上有一堆解答,但是介于MQTT系列函数等的特殊性,在网上有关mqttC编程的案例比较少,同时发生错误解答也会比较少,不像网络socket等的一些函数,网上有一堆,所以还是要在以往的学习中积累一些经验,遇到问题解决的办法也会多一些,在成功编译mqtt-paho.c后的make install 主要是将相应的库和头文件移到相应的编译器默认寻找的地方,方便编译和运行。但是由于这个命令需要sudo 权限,如果没有权限或者不愿意用权限,可以像我一样用链接选项和export…
在建立publish和subscribe通信时,publish端发送的消息在subscribe端可能会出现多余字符串“Packet.c”或者其一部分(在源字符串后面)(在直接打印receive_msg->payload时),使用mqtt.fx作为publish也会出现,解决办法(既然知道有效字符穿的长度->payloadlen,可以用循环字符打印,如上程序所示。)


推荐阅读
  • 在Docker中,将主机目录挂载到容器中作为volume使用时,常常会遇到文件权限问题。这是因为容器内外的UID不同所导致的。本文介绍了解决这个问题的方法,包括使用gosu和suexec工具以及在Dockerfile中配置volume的权限。通过这些方法,可以避免在使用Docker时出现无写权限的情况。 ... [详细]
  • imx6ull开发板驱动MT7601U无线网卡的方法和步骤详解
    本文详细介绍了在imx6ull开发板上驱动MT7601U无线网卡的方法和步骤。首先介绍了开发环境和硬件平台,然后说明了MT7601U驱动已经集成在linux内核的linux-4.x.x/drivers/net/wireless/mediatek/mt7601u文件中。接着介绍了移植mt7601u驱动的过程,包括编译内核和配置设备驱动。最后,列举了关键词和相关信息供读者参考。 ... [详细]
  • 云原生边缘计算之KubeEdge简介及功能特点
    本文介绍了云原生边缘计算中的KubeEdge系统,该系统是一个开源系统,用于将容器化应用程序编排功能扩展到Edge的主机。它基于Kubernetes构建,并为网络应用程序提供基础架构支持。同时,KubeEdge具有离线模式、基于Kubernetes的节点、群集、应用程序和设备管理、资源优化等特点。此外,KubeEdge还支持跨平台工作,在私有、公共和混合云中都可以运行。同时,KubeEdge还提供数据管理和数据分析管道引擎的支持。最后,本文还介绍了KubeEdge系统生成证书的方法。 ... [详细]
  • 本文介绍了Linux系统中正则表达式的基础知识,包括正则表达式的简介、字符分类、普通字符和元字符的区别,以及在学习过程中需要注意的事项。同时提醒读者要注意正则表达式与通配符的区别,并给出了使用正则表达式时的一些建议。本文适合初学者了解Linux系统中的正则表达式,并提供了学习的参考资料。 ... [详细]
  • FeatureRequestIsyourfeaturerequestrelatedtoaproblem?Please ... [详细]
  • Linux如何安装Mongodb的详细步骤和注意事项
    本文介绍了Linux如何安装Mongodb的详细步骤和注意事项,同时介绍了Mongodb的特点和优势。Mongodb是一个开源的数据库,适用于各种规模的企业和各类应用程序。它具有灵活的数据模式和高性能的数据读写操作,能够提高企业的敏捷性和可扩展性。文章还提供了Mongodb的下载安装包地址。 ... [详细]
  • Ubuntu安装常用软件详细步骤
    目录1.GoogleChrome浏览器2.搜狗拼音输入法3.Pycharm4.Clion5.其他软件1.GoogleChrome浏览器通过直接下载安装GoogleChro ... [详细]
  • 在Kubernetes上部署JupyterHub的步骤和实验依赖
    本文介绍了在Kubernetes上部署JupyterHub的步骤和实验所需的依赖,包括安装Docker和K8s,使用kubeadm进行安装,以及更新下载的镜像等。 ... [详细]
  • 本文介绍了Python高级网络编程及TCP/IP协议簇的OSI七层模型。首先简单介绍了七层模型的各层及其封装解封装过程。然后讨论了程序开发中涉及到的网络通信内容,主要包括TCP协议、UDP协议和IPV4协议。最后还介绍了socket编程、聊天socket实现、远程执行命令、上传文件、socketserver及其源码分析等相关内容。 ... [详细]
  • 关于我们EMQ是一家全球领先的开源物联网基础设施软件供应商,服务新产业周期的IoT&5G、边缘计算与云计算市场,交付全球领先的开源物联网消息服务器和流处理数据 ... [详细]
  • ZSI.generate.Wsdl2PythonError: unsupported local simpleType restriction ... [详细]
  • 推荐系统遇上深度学习(十七)详解推荐系统中的常用评测指标
    原创:石晓文小小挖掘机2018-06-18笔者是一个痴迷于挖掘数据中的价值的学习人,希望在平日的工作学习中,挖掘数据的价值, ... [详细]
  • 本文介绍了计算机网络的定义和通信流程,包括客户端编译文件、二进制转换、三层路由设备等。同时,还介绍了计算机网络中常用的关键词,如MAC地址和IP地址。 ... [详细]
  • 成功安装Sabayon Linux在thinkpad X60上的经验分享
    本文分享了作者在国庆期间在thinkpad X60上成功安装Sabayon Linux的经验。通过修改CHOST和执行emerge命令,作者顺利完成了安装过程。Sabayon Linux是一个基于Gentoo Linux的发行版,可以将电脑快速转变为一个功能强大的系统。除了作为一个live DVD使用外,Sabayon Linux还可以被安装在硬盘上,方便用户使用。 ... [详细]
  • 本文介绍了在Linux下安装和配置Kafka的方法,包括安装JDK、下载和解压Kafka、配置Kafka的参数,以及配置Kafka的日志目录、服务器IP和日志存放路径等。同时还提供了单机配置部署的方法和zookeeper地址和端口的配置。通过实操成功的案例,帮助读者快速完成Kafka的安装和配置。 ... [详细]
author-avatar
叶子已经不是木头的了
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有