塞上长城空自许
镜中衰鬓已先斑
前面的博文中已经讲了如何安装MQTT的环境,以及如何进行测试,并给出了一个C语言的小例子。今天再讲讲paho.mqtt.c中一些常用接口的使用以及实现一个命令控制及回显功能。
这里讲的不详细,如果有读者读到了感觉不太懂的话,需要先了解一下MQTT的的工作机制。
int MQTTClient_create(MQTTClient* handle, const char* serverURI, const char* clientId, int persistence_type, void* persistence_context);
对传入的handle进行初始化,绑定服务器地址,绑定当前客户端的id,最后面两个参数我也不知道干嘛的。。。
int MQTTClient_connect(MQTTClient handle, MQTTClient_connectOptions* options);
设置连接参数,比如:
MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer;
conn_opts.keepAliveInterval = 60;
conn_opts.cleansession = 1;
MQTTClient_connect(client, &conn_opts);
int MQTTClient_subscribe(MQTTClient handle, const char* topic, int qos);
订阅话题,最后哪个数字我也不知道干嘛的。。。
int MQTTClient_receive(MQTTClient handle, char** topicName, int* topicLen, MQTTClient_message** message, unsigned long timeout);
很简单,接收发布者在topic下发布的消息。
example:
char *cli_topic = nullptr;
int cli_topic_len;
MQTTClient_message *receive_msg = nullptr;
MQTTClient_receive(client, &cli_topic, &cli_topic_len, &receive_msg, 100000);
ptr = (char *)receive_msg->payload;
for (i = 0; i < receive_msg->payloadlen; i++)
message[i] = *ptr++;
message[i] = '\0';
int MQTTClient_publishMessage(MQTTClient handle, const char* topicName, MQTTClient_message* message, MQTTClient_deliveryToken *deliveryToken);
发布消息。
int MQTTClient_waitForCompletion(MQTTClient handle, MQTTClient_deliveryToken mdt, unsigned long timeout);
等待消息发送完成。
MQTTClient_unsubscribe(MQTTClient handle, const char* topic);
int MQTTClient_disconnect(MQTTClient handle, int timeout);
void MQTTClient_destroy(MQTTClient* handle);
这个看了前面就懂了,释放资源的。
前面关于接口的介绍差不多已经讲了通信的过程,这里的难点其实就是如何将MQTT这种“单向”通信的方式写成“同步双向的”,MQTT原来的通信方式是:
可以看到,MQTT的这种通信模式其实是“单向通信”,即同时只能服务端向客户端发送消息的,而如果要实现命令控制的话,我们得实现以下流程:
下面给出一个例子:
控制端:
#include "base.h"
int main(int argc, char **argv) {
char message[1000000];
send_command(argv[1], TOPIC1, "client"); // 省略实现细节,参考paho.mqtt.c接口介绍
recv_command(message, TOPIC2, "client"); // 省略实现细节,参考paho.mqtt.c接口介绍
printf("%s\n", message);
return 0;
}
被控制端:
#include
#include
#include
#include "base.h"
int main() {
char message[100];
char command[100];
char info[1000000];
recv_command(message, TOPIC1, "server"); // 省略实现细节,参考paho.mqtt.c接口介绍
sprintf(command, "%s 1> a.txt", message);
system(command);
usleep(100000);
int fd = open("a.txt", O_RDONLY);
int len = -1;
while (len) {
char buff[1024] = {'\0'};
len = read(fd, buff, sizeof(buff));
strcat(info, buff);
}
printf("%s\n", info);
send_command(info, TOPIC2, "server"); // 省略实现细节,参考paho.mqtt.c接口介绍
close(fd);
system("rm a.txt");
return 0;
}
这里有个细节,被控制端收到命令后,阻塞一段时间后才继续,这是因为在往某个话题发布消息前,必须已经有客户端先订阅了该话题,不然消息会发不出去,客户端也接收不到。
效果图:
启动服务端,注意服务端所在路径:
客户端输入命令,得到返回结果: