MQTT同步使用

Mqtt C中分为同步访问异步访问模式

同步访问的时候,请求会阻塞到访问处,知道有结果返回;
异步访问的时候,会将请求委托给Mqtt c client然后直接返回(零等待),最后结果返回之后,会回调对应的回调函数。
异步使用介绍:MQTT异步使用

一:结构体

1.结构体MQTTClient

定义: typedef void* MQTTClient;
含义:代表MQTT客户端的句柄,成功调用MQTTClient_create函数后会得到有效的客户端句柄。

使用声明:

MQTTClient client;

2.结构体MQTTClient_connectOptions

typedef struct
{
char struct_id[4];//结构体的识别序列,必须为MQTC
int struct_version;//结构体版本
/**
在0,1,2,3,4,5中取值:
0-表示没有SSL选项且没有serverURIs;
1-表示没有serverURIs;
2-表示没有MQTTVersion
3-表示没有返回值;
4-表示没有二进制密码选项
*/
int keepAliveInterval;
/**
在这段时间内没有数据相关的消息时,客户端发送一个非常小的MQTT“ping”消息,服务器将会确认这个消息
*/
int cleansession;
/**
当cleansession为true时,会话状态信息在连接和断开连接时被丢弃。 将cleansession设置为false将保留会话状
态信息
*/
int reliable;
/*
将该值设置为true意味着必须完成发布的消息(已收到确认),才能发送另一个消息
*/
MQTTClient_willOptions* will;
/*
如果程序不使用最后的意愿和遗嘱功能,请将此指针设置为NULL。
*/
const char* username;//用户名
const char* password;//密码
int connectTimeout;//允许尝试连接的过时时间
int retryInterval;//尝试重连的时间
MQTTClient_SSLOptions* ssl;
/*
如果程序不使用最后的ssl,请将此指针设置为NULL。
*/
int serverURIcount;

char* const* serverURIs;
/*
连接服务器的url,以protocol:// host:port为格式
*/
int MQTTVersion;
/*
MQTT的版本,MQTTVERSION_3_1(3),MQTTVERSION_3_1_1 (4) 
*/
struct
{
const char* serverURI;   
int MQTTVersion;     
int sessionPresent;  
} returned;
  struct {
  int len;            
const void* data;  
} binarypwd;
} MQTTClient_connectOptions;

使用方法

MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer;
初始化的值一般固定为下方数据:
#define MQTTClient_connectOptions_initializer { {'M', 'Q', 'T', 'C'}, 4, 60, 1, 1, NULL, NULL, NULL, 30, 20, NULL, 0, NULL, 0}

3.MQTTClient_message

typedef struct
{
    char struct_id[4];//结构体的识别序列,必须为MQTM
    int struct_version;//结构体的版本,必须为0
    int payloadlen;//MQTT信息的长度
    void* payload;//指向消息负载的指针
    int qos;//服务质量
    int retained;//保留标志
    int dup;dup//标志指示这个消息是否是重复的。 只有在收到QoS1消息时才有意义。 如果为true,则客户端应用程序应采取适当的措施来处理重复的消息。
    int msgid;//消息标识符通常保留供MQTT客户端和服务器内部使用。
} MQTTClient_message;

使用

MQTTClient_message pubmsg = MQTTClient_message_initializer;
初始化未下面的值
#define MQTTClient_message_initializer { {'M', 'Q', 'T', 'M'}, 0, 0, NULL, 0, 0, 0, 0 

二:库函数

1.MQTTClient_create

DLLExport int MQTTClient_create(MQTTClient* handle, const char* serverURI, const char*clientId,int persistence_type, void* persistence_context);

作用:该函数创建了一个用于连接到特定服务器,使用特定持久存储的MQTT客户端

MQTTClient* handle 执行MQTT客户端的句柄,在函数执行成功后,在内部被赋值
const char* serverURI 指定要连接服务器,格式为其格式为protocol://host:port,例如tcp://localhost:1883
const char* clientId 客户端标识符(clientId)是一个以空结尾的 UTF-8 编码字符串,客户端连接到服务器时将它传递过去。
int persistence_type 客户端所使用的持久类型。MQTTCLIENT_PERSISTENCE_NONE-使用内存持久化
void* persistence_context 如果应用程序使用的是MQTTCLIENT_PERSISTENCE_NONE持久化,该参数不使用,而且值应该设置为NULL

2.MQTTClient_setCallbacks

DLLExport int MQTTClient_setCallbacks(MQTTClient handle, void* context, MQTTClient_connectionLost* cl,MQTTClient_messageArrived* ma, MQTTClient_deliveryComplete* dc);

作用:该函数为特定的客户端创建回调函数。如果您的客户端应用程序不使用特定的回调函数,请将相关参数设置为NULL。 调用MQTTClient_setCallbacks()使客户端进入多线程模式。 任何必要的消息确认和状态通信都在后台处理,而不需要客户端应用程序的任何干预。

MQTTClient handle 指向MQTT客户端句柄的指针。
void* context  指向任何应用程序特定上下文的指针。 上下文指针被传递给每个回调函数,以提供对回调中的上下文信息的访问
MQTTClient_connectionLost* cl   指向MQTTClient_connectionLost()回调函数的指针。 如果您的应用程序不处理断开连接,您可以将其设置为NULL
MQTTClient_messageArrived* ma   指向MQTTClient_messageArrived()回调函数的指针。 当您调用MQTTClient_setCallbacks()时,必须指定此回调函数
MQTTClient_deliveryComplete* dc 指向MQTTClient_deliveryComplete()回调函数的指针。 如果您的应用程序同步发布,或者您不想检查是否成功发送,则可以将其设置为NUL

3.MQTTClient_connect

DLLExport int MQTTClient_connect(MQTTClient handle, MQTTClient_connectOptions* options);

作用:此函数尝试使用指定的选项将先前创建的客户端连接到MQTT服务器。

MQTTClient handle 指向MQTT客户端句柄的指针
MQTTClient_connectOptions* options options	指向有效的MQTTClient_connectOptions结构的指针

4.MQTTClient_subscribe

DLLExport int MQTTClient_subscribe(MQTTClient handle, const char* topic, int qos);

作用:此功能尝试将客户订阅到单个主题,该主题可能包含通配符。 此函数还指定服务质量。

MQTTClient handle 指向MQTT客户端句柄的指针。句柄被成功从函数中返回的客户端引用所填充
topic 订阅的主题,可使用通配符
qos	订阅的请求服务质量

5.MQTTClient_publishMessage

DLLExport int MQTTClient_publishMessage(MQTTClient handle, const char* topicName, MQTTClient_message* msg, MQTTClient_deliveryToken* dt);

作用:此函数尝试将消息发布到给定的主题

MQTTClient handle 指向MQTT客户端句柄的指针
const char* topicName 与信息相关的主题
MQTTClient_message* msg 指向有效的 MQTTClient_message 结构的指针, 其中包含要发布消息的有效负载和属性
MQTTClient_deliveryToken* dt 指向MQTTClient_deliveryToken的指针。当函数成功返回时,dt会被赋值为代表消息的token。如果程序中没有使用传递token,将其设置为NULL

6.MQTTClient_waitForCompletion

DLLExport int MQTTClient_waitForCompletion(MQTTClient handle, MQTTClient_deliveryToken dt, unsigned long timeout);

作用:客户端应用程序调用此函数来将主线程的执行与消息的完成发布同步。 被调用时,MQTTClient_waitForCompletion()阻塞执行,直到消息成功传递或已超过指定的时间。

MQTTClient handle 指向MQTT客户端句柄的指针。句柄被成功从函数中返回的客户端引用所填充
MQTTClient_deliveryToken dt 代表消息的MQTTClient_deliveryToken用来检测是否成功传递。传递token由发布函数MQTTClient_publish () 和 MQTTClient_publishMessage ()所产生
unsigned long timeout 等待的最大毫秒数

7.MQTTClient_receive

DLLExport int MQTTClient_receive(MQTTClient handle, char** topicName, int* topicLen, MQTTClient_message** message,unsigned long timeout);

仅当客户端应用程序未设置回调方法为支持异步接收消息。使用此函数允许单线程要编写的客户端订阅程序。当调用这个函数时阻塞,直到下一条消息到达或指定超时过期

MQTTClient handle 是执行函数MQTTClient_create函数返回的有效句柄
char** topicName 指向主题的指针的地址 , 执行后会把接受到的数据的主题名称放入这个参数
int* topicLen 主题的长度 , 执行后会吧接受到的主题的长度放到这个函数
MQTTClient_message** message 指向接收到的消息的指针的地址,应用程序通过设置消息指向接收到的消息。如果超时超时,指针被设置为NULL。 接受到的数据保存到这个地址中
unsigned long timeout 超时时间

三:示例

1:发布端

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<errno.h>
#include<unistd.h>
#include"MQTTClient.h"

int main(int argc, char**argv)
{
        char *address="tcp://localhost:1883";
        char *client_id="publish_client";
        char *topic="mqtt_examples";
        char buf[1024];
        const int time_out=1000;
        int rv; 
        int QOS=1;

        MQTTClient client;
        MQTTClient_connectOptions conn_opts=MQTTClient_connectOptions_initializer;
        MQTTClient_message publish_msg=MQTTClient_message_initializer;
        MQTTClient_deliveryToken token;
    
        conn_opts.keepAliveInterval=60;
        conn_opts.cleansession=1;

        MQTTClient_create(&client, address, client_id, MQTTCLIENT_PERSISTENCE_NONE, NULL);
        if((rv=MQTTClient_connect(client, &conn_opts))!=MQTTCLIENT_SUCCESS)
        {   
                printf("MQTTClient_connect failure:%s\n",strerror(errno) );
                return 0;
        }    
        publish_msg.qos=QOS;
        publish_msg.retained=0;
        while(1)
        {    
                printf("enter the message you want to send:");
                fgets(buf,sizeof(buf), stdin);
                publish_msg.payload=(void *)buf;
                publish_msg.payloadlen=strlen(buf);
                MQTTClient_publishMessage(client, topic, &publish_msg, &token);
                printf("waiting for %d seconds for publication of %s on topic %s for client with CLIENTD:%s\n",time_out/1000,buf,topic, client_id);
                rv = MQTTClient_waitForCompletion(client, token, time_out);
                printf("Message with delivery token %d delivery\n",rv);
                printf("%s\n",buf);
                sleep(3);
        }
}

2:订阅端

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<errno.h>
#include "MQTTClient.h"

int main()
{
        char *address = "tcp://localhost:1883";
        char *client_id = "client_sub";
        //char *topic = "mqtt_examples";
        char *topic = "#"; /*#代表订阅任何主题,不指定具体的主题名称可以用这个来接受所有主题的信息*/
        int rv, i;
        char *ptr = NULL;
        char *topic_any=NULL;
        int topic_len;

        MQTTClient client;
        MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer;
        MQTTClient_deliveryToken token;
        MQTTClient_message *receive_msg = NULL;
        conn_opts.keepAliveInterval = 60;
        conn_opts.cleansession = 1;

        if((rv= MQTTClient_create(&client, address, client_id, MQTTCLIENT_PERSISTENCE_NONE, NULL))<0)
        {
                printf("MQTTClient_create failure\n");
                return 0;
        } else {
                printf("MQTTCreate_create successfully\n");
        }
        if(rv = MQTTClient_connect(client, &conn_opts) != MQTTCLIENT_SUCCESS)
        {
                printf("MQTTClient_connnect failure: %d\n", rv);
                return 0;
        } else {
                printf("MQTTClient_connect succeessfuly\n");
        }
        MQTTClient_subscribe(client, topic, 1);
        while(1)
        {
                if ((rv = MQTTClient_receive(client, &topic_any, &topic_len, &receive_msg, 100000)) != MQTTCLIENT_SUCCESS)
                {
                        printf("MQTTClient_receive failur :%s\n", strerror(errno));
                        break;
                }
                printf("MQTTClient_receive successfully\n");
                ptr = receive_msg->payload;
                printf("Topic: %s\nTopic_len:%d\n", topic_any, topic_len);
                for(i=0; i<receive_msg->payloadlen; i++)
                {
                        putchar(*ptr++);
                }
                printf("\nmsg_len:%d\nmsg_id:%d", receive_msg->payloadlen, receive_msg->msgid);
                sleep(3);
        }
        printf("end\n");
        MQTTClient_disconnect(client, 10000);
        MQTTClient_destroy(&client);
        return 0;

}


四:总结

在linux下用C语言实现MQTT通信,要用到一系列MQTT函数,这些函数在Linux自带库中是没有的。
所以第一步:安装Paho C库
在git下下载paho C库git clone https://github.com/eclipse/paho.mqtt.c.git
如果安装出错可以参考https://blog.csdn.net/qudany10061700/article/details/86504294
各个动态库的作用
paho-mqtt3a : 一般实际开发中就是使用这个,a表示的是异步消息推送(asynchronous)。
paho-mqtt3as : as表示的是 异步+加密(asynchronous+OpenSSL)。
paho-mqtt3c : c 表示的应该是同步(Synchronize),一般性能较差,是发送+等待模式。
paho-mqtt3cs : 同上,增加了一个OpenSSL而已。

第二步,安装mqtt的服务器,可以用mosquitto
ubantu上可以用命令sudo snap install mosquitto来直接安装

编译时要指定头文件和库文件路径。以及库

gcc mqtt_publish.c -o mqtt_publish -lpaho-mqtt3c -L ./MQTT/paho.mqtt.c/ -I ./MQTT/paho.mqtt.c/src/

为了方便写一个生成多目标的Makefile,生成2个执行文件方便通信

ALL:mqtt_subscribe mqtt_publish
CC = gcc 
INC = /home/kayshi/paho.mqtt.c/src
LIB_PATH = /home/kayshi/paho.mqtt.c/
LIB = paho-mqtt3c
mqtt_subscribe:mqtt_subscribe.c
        $(CC) $< -o $@  -l$(LIB) -L$(LIB_PATH) -I$(INC)
mqtt_publish:mqtt_publish.c
        $(CC) $< -o $@  -l$(LIB) -L$(LIB_PATH) -I$(INC)
.PHONY clean:
        -rm -f mqtt_subscribe mqtt_publish

  • 14
    点赞
  • 58
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值