MQTT在RUST的使用整理(2024.6.18)
MQTT服务器搭建:开源的有两款,EMQX和Mosquitto,这里选择的是EMQX页面好看点,另一款Mosquitto据说比较轻型
ubuntu快速开始
一、EMQX安装
- 配置安装源
curl -s https://assets.emqx.com/scripts/install-emqx-deb.sh | sudo bash
- apt安装
sudo apt-get install emqx
- 启动(没有权限就加sudo)
emqx start
- 终端管理网站(可选,主要用于监控)
http://127.0.0.1:18083(用户名:admin,密码:public)
内网IP也是可以访问的18083网页端口的,如果要在内网之间进行通讯,请将防火墙端口开启
sudo ufw allow 1883
二、Rust使用MQTT
Rust中MQTT相关的库 paho-mqtt 、 rumqttc
以下用paho-mqtt,具体可以参照库的example进行更改。
这里做一个同时能够发送和接受的简易服务进行测试
新建一个项目
cargo new mqtt-one
首先定义几个常量,都是些通讯配置
/// 通讯IP和端口
const DFLT_BROKER:&str = "tcp://192.168.1.111:1883";
/// 客户端名称,自定义的,用于区分服务
const DFLT_CLIENT:&str = "test_center";
/// 发布的频道,定义为数组可以加多个,可自定义的
const DFLT_PU_TOPICS:&[&str] = &["Robot_Request"];
///订阅的频道,即监听、收信息的,可自定义的
const DFLT_SU_TOPICS:&[&str] = &["Robot_Reply","Robot_Request"];
/// QOS,通讯服务质量,有0、1、2 数字越高越严格,同时也越吃性能
const QOS:i32 = 2;
/// 与订阅的频道个数一致,这样可以根据不同频道使用不同通讯服务质量
const DFLT_QOS:&[i32] = &[0,2];
初始化mqtt连接方法
// 初始化mqtt连接,返回一个cli客户端
fn init_mqtt_connect()->Result<Client,Box<dyn std::error::Error>>{
let host = DFLT_BROKER.to_string();
// 设置客户端的配置,连接的URL,使用的ID
let create_opts = mqtt::CreateOptionsBuilder::new().server_uri(host).client_id(DFLT_CLIENT.to_string()).finalize();
// 创建一个连接的客户端
let cli = mqtt::Client::new(create_opts).expect("创建连接客户端出错");
// 设置连接时的配置参数
let conn_opts = mqtt::ConnectOptionsBuilder::new()
.keep_alive_interval(Duration::from_secs(20))
.clean_session(false)
.finalize();
// let conn_opts = mqtt::ConnectOptionsBuilder::new().keep_alive_interval(Duration::from_secs(20)).clean_session(true).finalize();
// 根据配置建立连接
if let Err(e) = cli.connect(conn_opts) {
println!("无法连接指定端口的mqtt服务器:\n\t{:?}", e);
}
// 客户端订阅频道
subscribe_topics(&cli);
Ok(cli)
}
订阅、发送、重联的API接口方法
/// 向频道发送信息
fn send_msg(cli:Client,content:String){
let msg = mqtt::Message::new(DFLT_PU_TOPICS[0], content.clone(), QOS);
let _tok = cli.publish(msg).expect("频道发布信息出错");
println!("发送信息:{}",content);
}
/// 订阅频道
fn subscribe_topics(cli: &mqtt::Client) {
if let Err(e) = cli.subscribe_many(DFLT_SU_TOPICS, DFLT_QOS) {
println!("Error subscribes topics: {:?}", e);
process::exit(1);
}
}
/// 尝试重联
fn try_reconnect(cli: &mqtt::Client) -> bool
{
println!("Connection lost. Waiting to retry connection");
for _ in 0..12 {
std::thread::sleep(Duration::from_millis(5000));
if cli.reconnect().is_ok() {
println!("Successfully reconnected");
return true;
}
}
println!("Unable to reconnect after several attempts.");
false
}
汇总
main.rs
文件
use std::{
process, thread, time::Duration
};
use paho_mqtt as mqtt;
use mqtt::Client;
const DFLT_BROKER:&str = "tcp://192.168.1.111:1883"; //通讯IP和端口
const DFLT_CLIENT:&str = "test_center"; //客户端名称,自定义的,用于区分服务
const DFLT_PU_TOPICS:&[&str] = &["Robot_Request"]; //发布的频道,定义为数组可以加多个
const DFLT_SU_TOPICS:&[&str] = &["Robot_Reply","Robot_Request"]; //订阅的频道,即监听、收信息的
const QOS:i32 = 2; //QOS 通讯质量,有0、1、2 数字越高越严格,同时也越吃性能
const DFLT_QOS:&[i32] = &[0,2]; //与订阅的频道个数一致,这样可以根据不同频道使用不同通讯质量
fn main() {
let content="Hello,MQTT".to_string(); //要发送的内容
let cli = init_mqtt_connect().expect("init error");
let cli_t=cli.clone();
// 建立一个线程,定时向主题发送信息
thread::spawn(move||{
println!("aha~~~~~~~~~");
for _i in 0..10{
send_msg(cli_t.clone(), content.clone());
std::thread::sleep(Duration::from_millis(1000));
}
});
let rx = cli.start_consuming();
// 这里应该会一直监听,接收信息
for msg in rx.iter() {
if let Some(msg) = msg {
let msg_string=msg.to_string();
// let last=(msg_string.len()).min(20);
println!("收到信息:{:?}", &msg_string);
}
else if !cli.is_connected() {
if try_reconnect(&cli) {
println!("Resubscribe topics...");
subscribe_topics(&cli);
} else {
break;
}
}
}
}
// 初始化mqtt连接,返回一个cli客户端
fn init_mqtt_connect()->Result<Client,Box<dyn std::error::Error>>{
let host = DFLT_BROKER.to_string();
// 设置客户端的配置,连接的URL,使用的ID
let create_opts = mqtt::CreateOptionsBuilder::new().server_uri(host).client_id(DFLT_CLIENT.to_string()).finalize();
// 创建一个连接的客户端
let cli = mqtt::Client::new(create_opts).expect("创建连接客户端出错");
// 设置连接时的配置参数
let conn_opts = mqtt::ConnectOptionsBuilder::new()
.keep_alive_interval(Duration::from_secs(20))
.clean_session(false)
.finalize();
// let conn_opts = mqtt::ConnectOptionsBuilder::new().keep_alive_interval(Duration::from_secs(20)).clean_session(true).finalize();
// 根据配置建立连接
if let Err(e) = cli.connect(conn_opts) {
println!("无法连接指定端口的mqtt服务器:\n\t{:?}", e);
}
// 客户端订阅频道
subscribe_topics(&cli);
Ok(cli)
}
/// 向频道发送信息
fn send_msg(cli:Client,content:String){
let msg = mqtt::Message::new(DFLT_PU_TOPICS[0], content.clone(), QOS);
let _tok = cli.publish(msg).expect("频道发布信息出错");
println!("发送信息:{}",content);
}
/// 订阅频道
fn subscribe_topics(cli: &mqtt::Client) {
if let Err(e) = cli.subscribe_many(DFLT_SU_TOPICS, DFLT_QOS) {
println!("Error subscribes topics: {:?}", e);
process::exit(1);
}
}
/// 尝试重联
fn try_reconnect(cli: &mqtt::Client) -> bool
{
println!("Connection lost. Waiting to retry connection");
for _ in 0..12 {
std::thread::sleep(Duration::from_millis(5000));
if cli.reconnect().is_ok() {
println!("Successfully reconnected");
return true;
}
}
println!("Unable to reconnect after several attempts.");
false
}
Cargo.toml
文件
[package]
name = "mqtt_one"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
paho-mqtt="0.12.3"