你眼里的月亮沉了又沉,
好似不堪重负的过去,
在埋怨毁了堤的眼泪,
于是,秋风又起,
于是,这落了一山的破碎,
全都有罪。
首先说下什么是MQTT(Message Queuing Telemetry Transport),它是一种轻量级的开放式消息传输协议,专门设计用于在低带宽、不稳定的网络环境中进行设备间通信。MQTT 最初由IBM开发,现在是OASIS(Organization for the Advancement of Structured Information Standards)的一个开放标准。
MQTT多用于物联网和传感器网络中,它主要具有以下特点:
-
轻量级: MQTT 是一种轻量级协议,对网络带宽和设备资源的要求较低。这使得它非常适用于资源受限的设备,如传感器和嵌入式系统。
-
发布/订阅模型: MQTT 使用发布/订阅模型,其中消息发布者(发布者)将消息发布到特定的主题(Topic),而订阅者则通过订阅特定主题来接收相关消息。这种模型使得设备之间的通信更为灵活。
-
可靠性: MQTT 具有一定的消息传递保证机制。它支持三种服务质量(QoS)级别,包括最多一次(At most once)、至少一次(At least once)和仅一次(Exactly once),允许根据应用程序的要求进行消息传递的可靠性配置。
-
持久性会话: 客户端可以选择创建持久性会话,以确保在重新连接时接收未接收的消息。
-
遗嘱消息: 客户端可以设置遗嘱消息,以便在其意外断开连接时通知其他订阅者。
-
广泛应用: MQTT 在物联网、远程监测、传感器网络等领域得到广泛应用,支持跨平台的消息传递。
在Linux应用开发中,我们使用MQTT可以采用移植一个MQTT的库,源码地址如下,如果下载慢可以把这个地址映射到gittee上再下载GitHub - eclipse/paho.mqtt.c: An Eclipse Paho C client library for MQTT for Windows, Linux and MacOS. API documentation: https://eclipse.github.io/paho.mqtt.c/
移植后我们就可以进行MQTT应用开发了,看代码前我们先简单说下MQTT的主要应用框架,我们开发的时候主要采用客户端的形式,也就是说我们所有的通信都相当与客户端,我们通过向服务端去订阅和发布消息进行通信,服务端可以理解成代理,它会将所有消息分发给每个订阅的人。使用时我们可以去下载个免费使用的服务端去测试我们的程序。
//! 消息订阅的回调函数
int on_messrecv(void* context, char* topicName, int topicLen, MQTTAsync_message* message)
{
printf("recv name:\ntopic:%s,payload:%s\n", topicName, (char*)message->payload);
//!< 这里我们可以把收到的消息放入自己定义的消息处理队列,然后单开个线程去处理这些消息
MQTTAsync_free(topicName);
MQTTAsync_free(message);
return 1;
}
void on_subscribe(void* context, MQTTAsync_successData* response)
{
//! 这个是订阅成功的回调函数
}
//! 连接 mqtt 服务器成功回调函数
void on_connect(void *context, MQTTAsync_successData* response)
{
MQTTAsync client = (MQTTAsync)context;
int ret;
MQTTAsync_responseOptions response_opt = MQTTAsync_responseOptions_initializer;
printf("Succeed in connecting to mqtt-server!\n");
response_opt.onSuccess = on_subscribe;
ret = MQTTAsync_subscribe(client, "你要订阅的主题名1", 1, &response_opt); //!< 订阅/pub主题消息
if(ret != MQTTASYNC_SUCCESS)
{
printf("Fail to sub operater !\n");
}
ret = MQTTAsync_subscribe(client, "你要订阅的主题名2", 1, &response_opt); //!< 订阅/pub主题消息
if(ret != MQTTASYNC_SUCCESS)
{
printf("Fail to sub dev self test!\n");
}
g_handle.is_connected = CONNECTED;
}
//! 断开与 mqtt 服务器链接回调函数
void dis_connect(void *context, MQTTAsync_failureData* response)
{
printf("Failed to connect mqtt-server!\n");
}
//! 向服务器发送消息成功回调函数
void on_send(void* context, MQTTAsync_successData* response)
{
printf("Send message to mqtt server success!\n");
}
//! mqtt 客户端初始化
int mqtt_client_init(void)
{
int ret;
MQTTAsync_connectOptions conn_opt = MQTTAsync_connectOptions_initializer; //!< 初始化连接选项
ret = MQTTAsync_create(&g_handle.client, "服务端的IP地址", "客户端ID", MQTTCLIENT_PERSISTENCE_NONE, NULL);
if(ret != MQTTASYNC_SUCCESS)
{
printf("Cannot create mqtt client!\n");
return -1;
}
ret = MQTTAsync_setCallbacks(g_handle.client, NULL, NULL, on_messrecv, NULL); //!< 初始化接收消息回调;
if(ret != MQTTASYNC_SUCCESS)
{
printf("Cannnot set call back function!\n");
return -1;
}
conn_opt.onSuccess = on_connect;
conn_opt.onFailure = dis_connect;
conn_opt.automaticReconnect = 1;
conn_opt.context = g_handle.client;
conn_opt.cleansession = 0;
conn_opt.username = "用户名";
conn_opt.password = "用户密码";
ret = MQTTAsync_connect(g_handle.client, &conn_opt);
//因为是异步的,当MQTTAsync_connect返回的时候只是代表底层代码对参数进行了检查
//当正确返回时,表示底层代码接收了该connect连接命令
if(ret != MQTTASYNC_SUCCESS)
{
printf("Cannot start a mqttt server connect!\n");
return -1;
}
return 0;
}
//! 发送主题
int mqtt_send_info(char *sub, char *data, int data_len)
{
MQTTAsync_message message = MQTTAsync_message_initializer;
MQTTAsync_responseOptions res_option = MQTTAsync_responseOptions_initializer;
message.payload = data;
message.payloadlen = data_len;
message.qos = 1;
res_option.onSuccess = on_send;
return MQTTAsync_sendMessage(g_handle.client, sub, &message, &res_option); //!< 发布消息
}