欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

MQTT 和 mosquitto 编程和移植

最编程 2024-10-17 14:45:13
...

知识点1:MQTT概述

概念:

Message Queuing TelemetryTransport,消息队列遥测传输。

特点:

1、针对移动终端设备的基于TCP/IP发布/订阅协议

2、可以保持长连接,具有一定的实时性,广泛应用物联网嵌入式中。

3、是基于TCP的应用层协议,要一直保持连接,功耗高

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

5、三种消息发布服务质量(QoS):(记!)

Ø“至多一次” ,(Qos0)消息发布完全依赖底层 TCP/IP 网络,会发生消息丢失或重复,这一级别可用于 对采集数据要求不严格的情况

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

Ø“只有一次” ,(Qos2)确保消息只到达一次,这一级别 可用于要求严格如涉及计费系统的情况,消息重 复或丢失都是不允许的

6、允许用户动态创建主题,零运维成本

MQTT及mosquitto编程及移植_服务端

7、数据不可知,不强求传输数据的类型与格式,保持灵活性

8、低带宽、高延迟、不稳定的网络等因素考虑在内

9、cs架构

替代了传统的客户端/服务器模型,可以实现以下解耦:

空间解耦,发布者和订阅者不需要知道对方

时间解耦,发布者和订阅者不需要同时运行(离线消息)

同步解耦,发布和接收都是异步通讯,无需停止任何处理

MQTT及mosquitto编程及移植_客户端_02

知识点2:MQTT协议介绍(了解)

MQTT及mosquitto编程及移植_客户端_03

1、固定控制报头

MQTT及mosquitto编程及移植_服务端_04

2、剩余数据长度

MQTT及mosquitto编程及移植_mosquitto_05

3、可变长度报头

MQTT及mosquitto编程及移植_服务端_06

4、有效数据载荷(真实数据)

知识点3:mosquitto移植

mosquitto是一个高质量轻量级的开源MQTT broker,目前支持MQTTv3.1和v3.1.1协议,

1、同时提供了一个C语言动态链接库libmosquitto

2、mosquitto由MQTT协议创始人之一的AndyStanford-Clark参与开发

安装及使用(linux/x86):

1、命令安装(优先选用)

安装:(重要!!!)

sudo apt-get install mosquitto
sudo apt-get install mosquitto-clients

使用:(重要!!!)

//往10.9.29.124服务器发布主题是"bj2401"的hello消息
mosquitto_pub -h 10.9.29.124 -t "bj2401" -m "hello"
//从10.9.29.124服务器订阅主题是"bj2401"的消息
mosquitto_sub -h 10.9.29.124 -t "bj2401"

MQTT及mosquitto编程及移植_mosquitto_07

注意:如果连接被拒绝,修改配置文件(/etc/mosquitto/mosquitto.conf),增加四行信息。

1、打开配置文件
    sudo gedit /etc/mosquitto/mosquitto.conf
2、增加如下内容:
    allow_anonymous true
    
    listener 1883 0.0.0.0
    socket_domain ipv4
    protocol mqtt
3、重启服务
    sudo systemctl restart mosquitto

2、源码安装(了解)

步骤1:安装依赖库openssl

步骤2:安装依赖库libuuid

步骤3:安装mosquitto

安装及使用(linux/arm):

1、源码安装(只能选用)

安装:(了解)

参考《linux(开发板)移植

使用:(重要!!!)

步骤1:找到压缩包并在虚拟机解压

tar xvf mqtt_arm.tar.bz2

步骤2:将生成的服务器及客户端映射到开发板

MQTT及mosquitto编程及移植_mosquitto_08

步骤3:开发板启动服务器

./mosquitto

3.1如果报错:

MQTT及mosquitto编程及移植_mosquitto_09

解决方法:

先找到缺少的库的路径,然后增加到环境变量LD_LIBRARY_PATH

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/缺少的库的路径

解决方法:

echo "user root" >  user.conf
./mosquitto -c user.conf -v

步骤4:测试开发板上的服务器

./mosquitto -c user.conf -v 

MQTT及mosquitto编程及移植_服务端_10

步骤4:测试开发板上客户端

MQTT及mosquitto编程及移植_客户端_11

linux(开发板)移植:(了解)

步骤1:安装mosquitto的依赖包openssl

1.1找到源码包,下载到虚拟机,解压

1.2新建文件夹保存arm版本的opessl的库及头文件

mkdir openssl_arm

1.3配置编译安装

cd openssl-1.0.1e
./config   --prefix=/home/edu/.../openssl_arm
//修改makefile脚本看下图

make
make install

MQTT及mosquitto编程及移植_mosquitto_12

步骤2:安装mosquitto的依赖包libuuid

1.1找到源码包,下载到虚拟机,解压

1.2新建文6版本的libuuid的库及头文件

mkdir libuuid_arm

1.3配置编译安装

cd libuuid-1.0.3
./configure --host=arm-linux  CC=arm-linux-gcc --prefix=/home/edu/bj2303/mqtt/libuuid_arm
make
make install

步骤3:安装mosquitto

3.1找到源码包,下载到虚拟机,解压

3.2新建文件夹保存arm版本的mosquitto的库及头文件、服务器、客户端

mkdir mosquitto_arm

3.3配置

配置打开配置文件修改gedit config.mk

//行16:
CC=arm-linux-gcc
CXX=arm-linux-g++
prefix=/home/edu/bj2303/mqtt/mosquitto_arm
//133行
CFLAGS:=-I/home/edu/bj2303/mqtt/openssl_arm/include -I/home/edu/bj2303/mqtt/uuid_arm/include
LDFLAGS=-L/home/edu/bj2303/mqtt/openssl_arm/lib -lm -ldl -lssl -lcrypto -L/home/edu/bj2303/mqtt/uuid_arm/lib -luuid
 -lrt
//148行
BROKER_LIBS =-L/home/edu/bj2303/mqtt/openssl_arm/lib -lm -ldl -lssl -lcrypto -L/home/edu/bj2303/mqtt/uuid_arm/lib -luuid
PASSWD_LIBS =-L/home/edu/bj2303/mqtt/openssl_arm/lib -lssl -lcrypto
LIB_LIBS =-L/home/edu/bj2303/mqtt/openssl_arm/lib -lssl -lcrypto
//206行
BROKER_LIBS =-L/home/edu/bj2303/mqtt/openssl_arm/lib -lm -ldl -lssl -lcrypto -L/home/edu/bj2303/mqtt/uuid_arm/lib -luuid
PASSWD_LIBS =-L/home/edu/bj2303/mqtt/openssl_arm/lib -lssl -lcrypto
LIB_LIBS =-L/home/edu/bj2303/mqtt/openssl_arm/lib -lssl -lcrypto

3.4编译安装

make
sudo make install

MQTT及mosquitto编程及移植_服务端_13

知识点4:mosquitto编程(重要)

常用函数:

https://mosquitto.org/api/files/mosquitto-h.html

MQTT及mosquitto编程及移植_服务端_14

MQTT及mosquitto编程及移植_mosquitto_15

MQTT及mosquitto编程及移植_服务端_16

MQTT及mosquitto编程及移植_服务端_17

MQTT及mosquitto编程及移植_mqtt_18

MQTT及mosquitto编程及移植_客户端_19

发布客户端:

1、初始化

2、创建客户端

3、连接服务器

4、发布

5、销毁客户端

6、反初始化

#include <stdio.h>
#include <string.h>
#include <mosquitto.h>
int main(){

    //1、初始化
    mosquitto_lib_init();
    //2、创建客户端
    struct mosquitto *pub_client = mosquitto_new("pub",false,NULL);
    if(pub_client==NULL){
        printf("创建客户端失败");
        return -1;
    }
    //3、连接服务器
    int ret = mosquitto_connect(pub_client,"10.9.29.124",1883,6);
    if(ret != MOSQ_ERR_SUCCESS){
        printf("连接服务器失败");
        return -1;
    }
    //4、发布
    int mid=1;
    mosquitto_publish(pub_client,&mid,"bj2401",strlen("helloo"),"helloo",1,false);
    //5、销毁客户端
    mosquitto_destroy(pub_client);
    //6、反初始化
    mosquitto_lib_cleanup();
    return 0;
}

MQTT及mosquitto编程及移植_mosquitto_20

另一种实现:

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

#include <string.h>
int main(){

    system("mosquitto_pub -h 10.9.29.49 -t 'bj2401' -m 'hello' ");
    return 0;
}

订阅客户端:

1、初始化

2、创建客户端

3、连接服务器

4、订阅函数

5、消息回调

6、主事件循环

7、销毁客户端

8、反初始化

#include <stdio.h>
#include <mosquitto.h>
#include <string.h>
//消息回调
void callback_message(struct mosquitto *mosq, void *obj, const struct mosquitto_message *message){
    printf("recv:%s\n",(char *)message->payload);

}
int main(){

    //1、初始化
    mosquitto_lib_init();
    //2、创建客户端
    struct mosquitto *sub_client = mosquitto_new("sub",false,NULL);
    if(sub_client==NULL){
        printf("创建客户端失败");
        return -1;
    }
    //3、连接服务器
    int ret = mosquitto_connect(sub_client,"10.9.29.49",1883,6);
    if(ret != MOSQ_ERR_SUCCESS){
        printf("连接服务器失败");
        return -1;
    }
    //4、订阅函数
    int mid=1;
    mosquitto_subscribe(sub_client,&mid,"bj2401",1);

    //5、消息回调
    mosquitto_message_callback_set(sub_client,callback_message);

    //6、主事件循环
    mosquitto_loop_start(sub_client);
    mosquitto_loop_stop(sub_client,false);
    //7、销毁客户端
    mosquitto_destroy(sub_client);
    //8、反初始化
    mosquitto_lib_cleanup();
    return 0;
}

MQTT及mosquitto编程及移植_客户端_21

另一种写法:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <strings.h>
#include <sys/types.h>
int main(){
    int fd[2];
    pipe(fd);//创建无名管道
    pid_t pid=fork();
    if(pid<0)
        return -1;
    else if(pid==0){//子进程使用无名管道的写端,将其标准输出写到管道
        close(fd[0]);
        dup2(fd[1],1);
        system("mosquitto_sub -h 10.9.29.49 -t 'bj2401' ");
    }else{            //父进程读管道的读端,拿到订阅的消息,进行处理
        close(fd[1]);
        char buf[128]="";
        //订阅到的数据进程处理
        while(1)
            {
                bzero(buf,sizeof(buf));
                read(fd[0],buf,sizeof(buf));
                printf("recv:%s\n",buf);
            }
        
    }
    
    return 0;
}

推荐阅读