图解MQTT概念、mosquitto编译和部署 ,写代码,分别使用外网和本地服务器进行测试
前沿提要:
MQTT是什么不知道?
看这一篇:https://www.cnblogs.com/happybirthdaytoyou/p/10362336.html
阿里云官网玩不转?
看这一篇: https://www.cnblogs.com/happybirthdaytoyou/p/14065294.html
不会用代码连接阿里云?
看这一篇:https://www.cnblogs.com/happybirthdaytoyou/p/14074606.html
《1》
MQTT是什么?
两个客户端A和B,服务器负责中转消息。A订阅的话题,或者叫主题,即Topic,如果B也向服务器发送一条消息,且这个消息内含的主题就是A订阅过的主题,那么A就会收到B的这条消息。
上图看了俩软件界面,这就相当于俩客户端了,我上图的用意是让一个客户端订阅对方要发布消息的主题,这样一方就能收到另一方的消息了,
本质上这个消息是MQTT服务器负责转发过来的,两个客户端口并不直接通信,是间接通信。
参考: https://www.cnblogs.com/yangfengwu/p/7764667.html
下图是可用的MQTT测试服务器
《2》
mosquitto在Linux环境下的部署
转自 https://blog.csdn.net/lee_xuwei/article/details/95315936
使用传统源码安装步骤:
步骤1:
http://mosquitto.org/files/source/ 官网下载源码 mosquitto-1.6.3.tar.gz,放到Linux环境中。
解压(tar -xzvf mosquitto-1.6.3.tar.gz)。
进入解压后的目录内,找到主要配置文件config.mk,其中包含mosquitto的安装选项,
需要注意的是,默认情况下mosquitto的安装需要OpenSSL(一个强大的安全套接字层密码库)的支持,
若不需要SSL,则需要关闭config.mk里面与SSL功能有关的选项(WITH_TLS、WITH_TLS_PSK)。
步骤2:
make
make install(需要root权限),这里编译失败出现了一个问题:
error while loading shared libraries:libmosquitto.so.1 : cannot open shared object file: No such file or directory
所以问题很清楚,没有找到这个动态链接库。遇到这种问题就有两种情况:
1)确实没有这个库或者库的版本不对 。 2)这个库所在的路径不在系统查找范围内。
笔者感觉这个库名字很眼熟,果然在“make install”命令执行的打印信息中发现蛛丝马迹:
“install -s --strip-program=strip libmosquitto.so.1 /usr/local/lib/libmosquitto.so.1”
笔者在这个路径下,找到了该动态库,说明现在的问题应该是属于第二种情况(而且是官方的代码,也不应该会犯第一种问题),于是在网上找到了解决方案。
1) 如果共享库文件安装到了/lib或/usr/lib目录下, 那么需执行一下ldconfig命令。
ldconfig命令的用途,主要是在默认搜寻目录(/lib和/usr/lib)以及动态库配置文件/etc/ld.so.conf内所列的目录下,搜索出可共享的动态链接库(格式如lib*.so*), 进而创建出动态装入程序(ld.so)所需的连接和缓存文件。 缓存文件默认为/etc/ld.so.cache, 此文件保存已排好序的动态链接库名字列表。
2) 如果共享库文件安装到了/usr/local/lib(很多开源的共享库都会安装到该目录下)或其它"非/lib或/usr/lib"目录下, 那么在执行ldconfig命令前,还要把新共享库目录加入到共享库配置文件/etc/ld.so.conf中,如下:(需要root权限执行下面命令)
# cat /etc/ld.so.conf
include ld.so.conf.d/*.conf
# echo "/usr/local/lib" >> /etc/ld.so.conf
# ldconfig
(详情参阅http://blog.chinaunix.net/uid-26212859-id-3256667.html)
这里笔者就是使用第二种情况的办法,成功完成编译。
完成后会在系统命令行里发现mosquitto、mosquitto_sub、mosquitto_pub三个工具,(网上说有四个,还有一个mosquitto_passwd,用于管理密码,应该是没关闭SSL的原因),
分别用于启动代理、订阅消息和发布消息。
图示:我的ubuntu内相应文件夹所在路径
测试
步骤1:开启一个终端:输入“mosquitto”命令,结果如下图,服务启动,因为一直监听,所以不会看到命令行。
输入“mosquitto”如果报错,发现报错是端口已被使用,可以使用 "ps -e "查看进程和“netstat -apn | grep :1883”来查看谁占用端口,可使用“kill -s 9 pid号”杀死该进程,然后重新输入“mosquitto”命令即可得到上图正确结果。
步骤2:开启第二个终端,输入“mosquitto_sub -t 主题名 -i 用户名”,(后面的“-i 用户名可省略”)例如:mosquitto_sub -t mqtt 结果如图,由于一直监听,所以也不会看到命令行。
步骤3:开启第三个终端,输入“mosquitto_pub -t 主题名 -i 用户名 -m 要发送的消息”
(如果要发送的消息中有空格,需用引号括起来)
例如:mosquitto_pub -h localhost -t mqtt -m "hello world"
则第二个终端可以收到这条信息。笔者看到其命令行有文件传输,又尝试传一个文件(内容只有一句话),第二个终端会直接显示文件的内容(截图中“hello World”下面的那句话就是)。尝试一个大文件的传输,将一个7M的书传过去,首先是可以传,但是第二个窗口显示的全是乱码,传输的速度也是一个问题。
这里之所以会想到传文件是因为看到mosquitto_pub的命令参数中有关于把文件当做message传输的记录,
这里的文件上限默认是256M。逻辑中有对文件大小的判断,超过256M的文件则不传。不知道这里如果把这个值修改更大,会不会产生影响,笔者没有尝试,因为传7M的文件都感觉很慢。(这个问题在MQTT协议介绍中可以得到答案,MQTT文件长度的表示是用1至4个字节来表示,而其表示长度的方式又有特殊的加密方式,按照这种方式,其最大表示的长度为256M)
测试总结
三个终端,一个用来开启服务,一个执行mosquitto_sub来订阅消息,与服务器保持长连接,随时接收来自服务器推送的消息,最后一个终端则用来发布消息。这个测试的结果现在是正确的,但仍存在局限性,还有以下几个问题需要注意:
1)了解mosquitto_sub和mosquitto_pub命令背后是如何执行的,需要修改,订阅端的处理肯定不能仅仅是显示内容 到标准输出上。
2)了解mosquitto命令的逻辑,这里包含的内容很多,估计也是最难的。
3)这里的实验是在本地传输,需要做一个客户端出来(客户端可能是Android端或者MCU端),看是否可以正常传输,还有就是能传多大的数据,允许同时连入的客户数有多少(据说是20000以上)。
================================我的实操======我的实操==============================
使用ubuntu内的本地服务器测试:
也可以连接到通信猫的mqtt服务器:
ubuntu内的一个mqtt客户端进程向“pu”主题发布消息后, =》 ubuntu内的另一个mqtt客户端进程可以收到该消息,同时windows上的通信猫软件上的mqtt客户端也可以收到该消息。
下面贴上我的实验代码
makfile
.PHONY : rebuild clean $(TARGET) src = $(wildcard ./*.c)
CFLAGS += -I.
LIB += -lpthread -L/usr/local/lib/ -lmosquitto
CC = gcc
TARGET = HELLO-MQTT.out
OBJS := $(patsubst %.c,%.o,$(src)) $(TARGET) : $(OBJS)
$(CC) $(CFLAGS) $^ -o $@ $(LIB) $(OBJS) : %.o : %.c
$(CC) $(CFLAGS) -c $^ -o $@ clean :
$(RM) $(OBJS)
$(RM) $(TARGET)
@echo "clean" rebuild : clean $(TARGET)
@echo "rebuild"
pub.c
#include <stdio.h>
#include <stdlib.h>
#include <mosquitto.h>
#include <string.h> //#define HOST "localhost" //可以改为自己MQTT的服务器地址 如:#define HOST "l06.xxx.xxx.xxx" #define ubuntu_lcoal_server "127.0.0.1"
#define mqtt_test_server "120.76.100.197" // you can also use "test.mosquitto.org" 1883 #ifndef local
#define HOST mqtt_test_server
#define PORT 18831
#else
#define HOST ubuntu_lcoal_server
#define PORT 1883
#endif #define topic "pu" #define KEEP_ALIVE 60 #define MSG_MAX_SIZE 512 bool session = true; int main()
{
char buff[MSG_MAX_SIZE];
struct mosquitto *mosq = NULL;
//libmosquitto 库初始化
mosquitto_lib_init();
//创建mosquitto客户端
mosq = mosquitto_new(NULL,session,NULL);
if(!mosq){
printf("create client failed..\n");
mosquitto_lib_cleanup();
return 1;
}
//连接服务器
if(mosquitto_connect(mosq, HOST, PORT, KEEP_ALIVE)){
fprintf(stderr, "Unable to connect.\n");
return 1;
} int loop = mosquitto_loop_start(mosq);
if(loop != MOSQ_ERR_SUCCESS)
{
printf("mosquitto loop error\n");
return 1;
}
while(fgets(buff, MSG_MAX_SIZE, stdin) != NULL)
{
/*发布消息 topic 主题:"pu"*/
mosquitto_publish(mosq,NULL, topic ,strlen(buff)+1,buff,0,0);
memset(buff,0,sizeof(buff));
}
mosquitto_destroy(mosq);
mosquitto_lib_cleanup();
return 0;
}
sub.c
#include <stdio.h>
#include <stdlib.h>
#include <mosquitto.h>
#include <string.h> //#define HOST "localhost" //可以改为自己MQTT的服务器地址 如:#define HOST "106.xxx.xxx.xxx" #define ubuntu_lcoal_server "127.0.0.1"
#define mqtt_test_server "120.76.100.197" #ifndef local
#define HOST mqtt_test_server
#define PORT 18831
#else
#define HOST ubuntu_lcoal_server
#define PORT 1883
#endif #define KEEP_ALIVE 60 bool session = true; void my_message_callback(struct mosquitto *mosq, void *userdata, const struct mosquitto_message *message)
{
if(message->payloadlen){
printf("%s %s", message->topic, message->payload);
}else{
printf("%s (null)\n", message->topic);
}
fflush(stdout);
} void my_connect_callback(struct mosquitto *mosq, void *userdata, int result)
{
int i;
if(!result){
/* Subscribe to broker information topics on successful connect. */
printf(" Connect Success !\n");
mosquitto_subscribe(mosq, NULL, "pu", 2); //topic 主题:"pu"
}else{
fprintf(stderr, "Connect failed\n");
}
} void my_subscribe_callback(struct mosquitto *mosq, void *userdata, int mid, int qos_count, const int *granted_qos)
{
int i;
printf("Subscribed (mid: %d): %d", mid, granted_qos[0]);
for(i=1; i<qos_count; i++){
printf(", %d", granted_qos[i]);
}
printf("\n");
} void my_log_callback(struct mosquitto *mosq, void *userdata, int level, const char *str)
{
/* Pring all log messages regardless of level. */
printf("%s\n", str);
} int main()
{
struct mosquitto *mosq = NULL;
//libmosquitto 库初始化
mosquitto_lib_init(); //创建mosquitto客户端
mosq = mosquitto_new(NULL,session,NULL);
if(!mosq){
printf("create client failed..\n");
mosquitto_lib_cleanup();
return 1;
} //设置回调函数,需要时可使用
//mosquitto_log_callback_set(mosq, my_log_callback);
mosquitto_connect_callback_set(mosq, my_connect_callback);
mosquitto_message_callback_set(mosq, my_message_callback);
//mosquitto_subscribe_callback_set(mosq, my_subscribe_callback); //客户端连接服务器
if(mosquitto_connect(mosq, HOST, PORT, KEEP_ALIVE)){
fprintf(stderr, "Unable to connect.\n");
return 1;
} //循环处理网络消息
mosquitto_loop_forever(mosq, -1, 1); //end
mosquitto_destroy(mosq);
mosquitto_lib_cleanup(); return 0;
}
我当前的工作环境
备注:我当前的makefile编译的是pub.c或者是sub.c中的一个,编译pub.c的时候,先不要把sub.c放在当前目录,要不然会编译报错:出现两个main函数。
我的本意是pub.c和sub.c分别编译,得到两个可执行程序,然后一个发布,一个订阅,这样就可以借助MQTT来实现进程间通信了。
PS: 稍微改下makefile也可以的,这样就得到两个可执行程序了。 鉴于我现在只是在整理博客,就不来改了。
Ubuntu上的实验也可以做不少事,
现在有了mqtt, 还可以再加上sqlite、json、在线升级、低功耗处理,等等相关功能模块, 这些都是单片机产品物联网应用场景下常用的且紧密相关的。
.
图解MQTT概念、mosquitto编译和部署 ,写代码,分别使用外网和本地服务器进行测试的更多相关文章
- 移动端H5拍照代码实现及外网部署
最近的工作中,遇到了一个需求:对于无APP登陆权限的人员,提供拍照上传功能,以便生成更完善的出工记录.经研究讨论,决定实现的机制为:由合法的人员登陆APP认领相关工作任务,并生成当天当工作的唯一二维码 ...
- 总想自己动动手系列·2·本地和外网(Liunx服务器上部署的web项目)按照自定义的报文格式进行交互(完结篇)
一.准备工作 (1)创建一个web-project工程,部署本地可正常访问,部署在云服务上可访问. (2)理解如何在web.xml文件中配置过滤器,和创建一个自定义的过滤器. (3)懂得如何打war包 ...
- 总想自己动动手系列·1·本地和外网(Liunx服务器上部署的web项目)按照自定义的报文格式进行交互(准备篇)
一.准备工作 (1)有一台属于自己的云服务器,并成功部署和发布一个web项目(当然,本质上来说Java-Project也没问题),通过外网IP可以正常访问该web项目. 需要说明的是:任何web项目, ...
- Github Copilot 比在座各位更会写代码。jpg
之前大佬和我安利过 Copilot, 作为一个能用就行的践行者, 我一贯对这些东西都不太感兴趣. 就如我多年VS Code写各种编程语言, jetbrains 全家桶我都懒得搞~ 不过最近看到过Cha ...
- 腾讯云linux系统部署项目无法通过外网访问
最近尝试使用了一下腾讯去的linux系统服务器,但是却遇到各种问题,下面记录的问题是项目部署完成后却无法通过外网访问. 服务器:腾讯云 系统 :CentOS 8.0 64位 处理思路:通过度娘百般摸索 ...
- Spark入门实战系列--2.Spark编译与部署(上)--基础环境搭建
[注] 1.该系列文章以及使用到安装包/测试数据 可以在<倾情大奉送--Spark入门实战系列>获取: 2.Spark编译与部署将以CentOS 64位操作系统为基础,主要是考虑到实际应用 ...
- Spark编译与部署
Spark入门实战系列--2.Spark编译与部署(上)--基础环境搭建 [注] 1.该系列文章以及使用到安装包/测试数据 可以在<倾情大奉送--Spark入门实战系列>获取: 2.S ...
- 一文搭建自己博客/文档系统:搭建,自动编译和部署,域名,HTTPS,备案等
本文纯原创,搭建后的博客/文档网站可以参考: Java 全栈知识体系.如需转载请说明原处. 第一部分 - 博客/文档系统的搭建 搭建博客有很多选择,平台性的比如: 知名的CSDN, 博客园, 知乎,简 ...
- Spark入门实战系列--2.Spark编译与部署(中)--Hadoop编译安装
[注]该系列文章以及使用到安装包/测试数据 可以在<倾情大奉送--Spark入门实战系列>获取 .编译Hadooop 1.1 搭建环境 1.1.1 安装并设置maven 1. 下载mave ...
- Spark入门实战系列--2.Spark编译与部署(下)--Spark编译安装
[注]该系列文章以及使用到安装包/测试数据 可以在<倾情大奉送--Spark入门实战系列>获取 .编译Spark .时间不一样,SBT是白天编译,Maven是深夜进行的,获取依赖包速度不同 ...
随机推荐
- ABC348
A link 这道题就先输出整个的\(oox\),再输出剩一个两个的. 点击查看代码 #include<bits/stdc++.h> using namespace std; int n; ...
- 使用ollama本地部署gemma记录
1.官网https://ollama.com/安装ollama 2.先配置一下环境变量 不然下载的东西会默认丢在C盘里 3.cmd执行ollama run gemma:2b (使用后推荐直接下7b,2 ...
- idea快捷键Ctrl+alt+m:如何快速抽离部分方法
Ctrl+alt+m 效果如下图
- mp实现一个自连接查询
起因是我设置了一个考核表结构,其中包含指标值,指标当前值,是主副指标等列. 后面我要进行考核的验收的时候,我发现验收要取得的是主当前指标值/主指标值以及副指标当前值/副指标值.如果想要让这两条数据一次 ...
- 【微信小程序】 列表查询功能
对应本地生活案例: https://www.bilibili.com/video/BV1834y1676P?p=52 HTML代码部分: 就是普通的wx-for指令遍历 <!--pages/cl ...
- 【Tutorial C】01 概述
历史 History 欢迎来到C语言的世界!C语言是一种强大的专业化编程语言,深受业余和专业编程人员的欢迎. 在学习之前先让我们了解和认识它! C语言的原型是A语言(ALGOL 60语言). 1963 ...
- python进程绑定CPU的一些Demo
从https://www.cnblogs.com/devilmaycry812839668/p/17066212.html中知道如何对python进程设置CPU绑定,本文对此进行一些延伸,给出一些例子 ...
- 如何使用git通过ssh协议拉取gitee上的项目代码——如何正确的免密使用git
如何在gitee网站上生成/添加SSH公钥见教程: 生成/添加SSH公钥 测试公私秘钥是否成功: ssh -T git@gitee.com ============================== ...
- [CEOI 2013] 千岛之国 / Adritic 题解
前言 题目链接:洛谷. 题意简述 你被困在一个被划分为 \(2500 \times 2500\) 的二维平面内!平面上有 \(n\)(\(n \leq 250000\))个岛屿你可以停留,你可以在这些 ...
- Apache DolphinScheduler 3.1.8 保姆级教程【安装、介绍、项目运用、邮箱预警设置】轻松拿捏!
概述 Apache DolphinScheduler 是一个分布式易扩展的可视化 DAG 工作流任务调度开源系统.适用于企业级场景,提供了一个可视化操作任务.工作流和全生命周期数据处理过程的解决方案. ...