空光远流浪
铜柱从年消
概念
MQTT
MQTT是一种轻量级的、灵活的网络协议,适用于IoT场景,其优点如下:
- 这个轻量级协议可在严重受限的设备硬件和高延迟/带宽有限的网络上实现
- 它的灵活性使得为 IoT 设备和服务的多样化应用场景提供支持成为可能
为什么IoT场景下不使用其他网络协议,主要还是没钱,物联网设备不可能使用高昂的硬件,便宜的东西性能就差,因此必须压榨性能。而例如HTTP协议,是需要保持客户端和服务器之间的连接的,这对物联网设备来说是不经济的。物联网环境下,功耗低,网络带宽低,延迟高,不能支持复杂的网络协议,而MQTT恰好可以使用于此。
原理
MQTT的架构是基于发布和订阅模型实现的,在MQTT网络中,定义了一个消息代理,多个客户端。代理是一个服务器,它从客户端接收所有消息,然后将这些消息路由到相关的目标客户端。客户端连接到代理,订阅代理中的消息主题;客户端可以将消息和主题发送给代理,发布某个主题内的消息;代理将消息转发给每个订阅该主题的客户端。
实践
mac下安装和使用mosquitto
-
安装mosquitto
brew install mosquitto
-
启动mosquitto
brew services start mosquitto
-
一个终端订阅消息
mosquitto_sub -t "demo"
-
一个终端发布消息
mosquitto_pub -t "demo" -m "hello world!"
实现命令FTP功能
- 设计
- 客户端
- 要求用户验证
- 发布命令(发布‘命令’话题)
- 接收服务端传回的命令调用结果(订阅‘结果’话题)
- 服务端
- 预先设置用户名和密码
- 接收客户端命令(订阅‘命令’话题)并执行系统调用
- 发布调用结果(发布‘结果’话题)
- 客户端
-
利用mosquitto封装的接口实现功能
mosquitto的接口主要封装在mosquitto.h头文件中,利用cmake链接好libmosquitto库即可使用
CMakeLists如下:
cmake_minimum_required(VERSION 3.15) project(MosquittoFTP) set(CMAKE_CXX_STANDARD 14) link_libraries(/usr/local/Cellar/mosquitto/1.6.7/lib) add_executable(MosquittoFTP myoperator.cpp) target_link_libraries(MosquittoFTP -lmosquitto)
- 服务端
-
设置用户名密码
mosq = mosquitto_new(nullptr,session,nullptr); mosquitto_username_pw_set(mosq, "test", "123456");
-
处理命令的关键回调函数
//exec system call std::string exec(const char* cmd) { std::array<char, 128> buffer; std::string result; std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(cmd, "r"), pclose); if (!pipe) { throw std::runtime_error("popen() failed!"); } while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) { result += buffer.data(); } return result; } //exec client command void my_message_callback(struct mosquitto *mosq, void *userdata, const struct mosquitto_message *message) { if(message->payloadlen){ char *head = static_cast<char*>(message->payload); std::string command(head,head+message->payloadlen); std::cout << message->topic << " " << command << std::endl; std::string result = exec(head); //std::cout << result << std::endl; mosquitto_publish(mosq,nullptr,"Result:",result.length()+1,result.c_str(),0,0); }else{ std::cout << message->topic << " (NULL)" << std::endl; } }
-
-
客户端
-
验证
mosq = mosquitto_new(nullptr,session,nullptr); std::string username,password; std::cout << "Please input your username!" << std::endl; std::cin >> username; std::cout << "Please input your password!" << std::endl; std::cin >> password; mosquitto_username_pw_set(mosq, username.c_str(), password.c_str());
-
接收服务端回显结果
void my_message_callback(struct mosquitto *mosq, void *userdata, const struct mosquitto_message *message) { if(message->payloadlen){ char *head = static_cast<char*>(message->payload); std::string command(head,head+message->payloadlen); std::cout << message->topic << " " << command << std::endl; }else{ std::cout << message->topic << " (NULL)" << std::endl; } }
-
- 结果
- 服务端
- 客户端