Paho - Things MQTT C Cient implementation and Detailed

https://www.cnblogs.com/homejim/p/8196763.html

Outline

  In the article Paho - the realization MQTT C Cient , I describe how to create an open source project MQTTClient_pulish use Paho clients. But simply introduced the use method, and the client does not match the results presented before, today I will combine new examples, explain to you Paho use the primary process MQTT client.
  As described earlier, MQTT client divided into synchronous and asynchronous client client. Today is mainly on the synchronization client, structure or synchronization client as described in:

  1. Create a client object;
  2. Set MQTT option connection server;
  3. If the multi-thread (asynchronous mode) is set by using a callback function (see Asynchronous> Client Applications Synchronous VS);
  4. subscribing client needs received any topic;
  5. repeating the operation until the end:
    a release any information required by clients;.
    B handles all messages received;.
  6. disconnect the client;
  7. release all the memory used by the client.

achieve

  Well, directly on the code, MQTT simple synchronization client.

#include <pthread.h>
#include <stdio.h> #include <stdlib.h> #include <string.h> #include "MQTTClient.h" #if !defined(WIN32) #include <unistd.h> #else #include <windows.h> #endif #define NUM_THREADS 2 #define ADDRESS "tcp://localhost:1883" //更改此处地址 #define CLIENTID "aaabbbccc_pub" //更改此处客户端ID #define SUB_CLIENTID "aaabbbccc_sub" //更改此处客户端ID #define TOPIC "topic01" //更改发送的话题 #define PAYLOAD "Hello Man, Can you see me ?!" // #define QOS 1 #define TIMEOUT 10000L #define USERNAME "test_user" #define PASSWORD "jim777" #define DISCONNECT "out" int CONNECT = 1; volatile MQTTClient_deliveryToken deliveredtoken; void delivered(void *context, MQTTClient_deliveryToken dt) { printf("Message with token value %d delivery confirmed\n", dt); deliveredtoken = dt; } int msgarrvd(void *context, char *topicName, int topicLen, MQTTClient_message *message) { int i; char* payloadptr; printf("Message arrived\n"); printf(" topic: %s\n", topicName); printf(" message: "); payloadptr = message->payload; if(strcmp(payloadptr, DISCONNECT) == 0){ printf(" \n out!!"); CONNECT = 0; } for(i=0; i<message->payloadlen; i++) { putchar(*payloadptr++); } printf("\n"); MQTTClient_freeMessage(&message); MQTTClient_free(topicName); return 1; } void connlost(void *context, char *cause) { printf("\nConnection lost\n"); printf(" cause: %s\n", cause); } void *subClient(void *threadid){ long tid; tid = (long)threadid; printf("Hello World! It's me, thread #%ld!\n", tid); MQTTClient client; MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer; int rc; int ch; MQTTClient_create(&client, ADDRESS, SUB_CLIENTID, MQTTCLIENT_PERSISTENCE_NONE, NULL); conn_opts.keepAliveInterval = 20; conn_opts.cleansession = 1; conn_opts.username = USERNAME; conn_opts.password = PASSWORD; MQTTClient_setCallbacks(client, NULL, connlost, msgarrvd, delivered); if ((rc = MQTTClient_connect(client, &conn_opts)) != MQTTCLIENT_SUCCESS) { printf("Failed to connect, return code %d\n", rc); exit(EXIT_FAILURE); } printf("Subscribing to topic %s\nfor client %s using QoS%d\n\n" "Press Q<Enter> to quit\n\n", TOPIC, CLIENTID, QOS); MQTTClient_subscribe(client, TOPIC, QOS); do { ch = getchar(); } while(ch!='Q' && ch != 'q'); MQTTClient_unsubscribe(client, TOPIC); MQTTClient_disconnect(client, 10000); MQTTClient_destroy(&client); pthread_exit(NULL); } void *pubClient(void *threadid){ long tid; tid = (long)threadid; int count = 0; printf("Hello World! It's me, thread #%ld!\n", tid); //声明一个MQTTClient MQTTClient client; //初始化MQTT Client选项 MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer; //#define MQTTClient_message_initializer { {'M', 'Q', 'T', 'M'}, 0, 0, NULL, 0, 0, 0, 0 } MQTTClient_message pubmsg = MQTTClient_message_initializer; //声明消息token MQTTClient_deliveryToken token; int rc; //使用参数创建一个client,并将其赋值给之前声明的client MQTTClient_create(&client, ADDRESS, CLIENTID, MQTTCLIENT_PERSISTENCE_NONE, NULL); conn_opts.keepAliveInterval = 20; conn_opts.cleansession = 1; conn_opts.username = USERNAME; conn_opts.password = PASSWORD; //使用MQTTClient_connect将client连接到服务器,使用指定的连接选项。成功则返回MQTTCLIENT_SUCCESS if ((rc = MQTTClient_connect(client, &conn_opts)) != MQTTCLIENT_SUCCESS) { printf("Failed to connect, return code %d\n", rc); exit(EXIT_FAILURE); } pubmsg.payload = PAYLOAD; pubmsg.payloadlen = strlen(PAYLOAD); pubmsg.qos = QOS; pubmsg.retained = 0; while(CONNECT){ MQTTClient_publishMessage(client, TOPIC, &pubmsg, &token); printf("Waiting for up to %d seconds for publication of %s\n" "on topic %s for client with ClientID: %s\n", (int)(TIMEOUT/1000), PAYLOAD, TOPIC, CLIENTID); rc = MQTTClient_waitForCompletion(client, token, TIMEOUT); printf("Message with delivery token %d delivered\n", token); usleep(3000000L); } MQTTClient_disconnect(client, 10000); MQTTClient_destroy(&client); } int main(int argc, char* argv[]) { pthread_t threads[NUM_THREADS]; long t; pthread_create(&threads[0], NULL, subClient, (void *)0); pthread_create(&threads[1], NULL, pubClient, (void *)1); pthread_exit(NULL); } 

  In the code, I created two threads which handle client subscriptions and publishing clients.

Overall Comments

Next, I explain this simple client, which, in general the process is as follows:
The client process in general
  As shown in the general procedure is shown, after the client starts, will start the thread, create a subscription client, it listens for incoming messages, in after reaching the appropriate message triggers callback function to process the message; after starting a thread, to create a sending client for sending the message, each will determine whether to send a message before dropping as CONNECT = 0 then the It will be dropped, or send a message to topic01.

Subscribe client Detailed

  The following functions are completed subscription feature.

void *subClient(void *threadid)

Process probably as follows:

  The first step: Declare the client, and to their assignment by function;

MQTTClient client;
MQTTClient_create(&client, ADDRESS, SUB_CLIENTID, MQTTCLIENT_PERSISTENCE_NONE, NULL);

  Step two: Set the option to connect MQTT server;

MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer;

  Step 3: Set callback function;

MQTTClient_setCallbacks(client, NULL, connlost, msgarrvd, delivered);
//相应的回调函数connlost,msgarrvd,delivered我的代码中都有

  Step Four: Using Client and connectivity options for connecting to the server;

MQTTClient_connect(client, &conn_opts))

  Step Five subscribe topic;

MQTTClient_subscribe(client, TOPIC, QOS);

  A sixth step waits known input 'Q' or 'q';

    do 
    {
        ch = getchar();
    } while(ch!='Q' && ch != 'q');

  A sixth step waits until the input 'Q' or 'q';

    do 
    {
        ch = getchar();
    } while(ch!='Q' && ch != 'q');

  Step Seven unsubscribe;

MQTTClient_unsubscribe(client, TOPIC);

  Step VIII disconnect the client;

 MQTTClient_disconnect(client, 10000);

  Step ninth releases all memory used by the client;

MQTTClient_destroy(&client);

  At this point, the client subscription is over. General subscription clients generally are like structure. The difference is that on the personalization of the callback function.

Detailed sending client

  The following functions are complete functional sent.

void *pubClient(void *threadid)

Process probably as follows:

  The first step: Declare the client, and to their assignment by function;

MQTTClient client;
MQTTClient_create(&client, ADDRESS, CLIENTID, MQTTCLIENT_PERSISTENCE_NONE, NULL);

  Step two: Set the option to connect MQTT server;

MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer;

  The third step: Use client connectivity options and connect to the server;

MQTTClient_connect(client, &conn_opts)

  A fourth step of setting the attribute to send a message;

    pubmsg.payload = PAYLOAD;
    pubmsg.payloadlen = strlen(PAYLOAD);
    pubmsg.qos = QOS;
    pubmsg.retained = 0;

  A fifth step cycle to send a message;

   MQTTClient_publishMessage(client, TOPIC, &pubmsg, &token);

  The sixth step has been waiting to exit the client when CONNECT = 0;

  Step 7 disconnect the client;

    MQTTClient_disconnect(client, 10000);

  Step eight free all memory used by the client;

 MQTTClient_destroy(&client);

  At this point, the client sends over. Can be used when the general sends the client the general structure is also the case, but asynchronous client may be slightly different, the design is nothing more than a callback function, and then connect, disconnect the callback function to do some operations only, specific studies may own.


  To give you a more in-depth understanding, I've learned some of the functions and structures generally below explain a bit.

Related structures

MQTTClient

Definitions: typedef void * MQTTClient;
meaning: MQTT handle on behalf of the client. After a successful call MQTTClient_create (), you can get a valid client handle.


MQTTClient_connectOptions

definition:

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; 

Meaning: the option to set the connection structure of MQTTClient.


MQTTClient_message

definition:

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;

Meaning: The structure represents the MQTT information.

Detailed correlation function

MQTTClient_create

definition:

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

Role: This function creates a connection to a specific server, using a specific persistent storage MQTT client.

parameter meaning
handle A pointer to MQTT client handle. Successfully handle is returned from the client function reference filled
and server Null-terminated string which specifies that the client will connect to the server. The format is protocol: // host: port. Now the (protocol) protocol must be tcp or ssl, and the host can be specified as an IP address or domain name. For example, to use the default server port to connect to MQTT running on the local computer, specify for the tcp: // localhost: 1883.
clientId Client Identifier (clientId) is connected to a server in UTF-8 encoded string, the end of the empty client passes over it.
persistence_type Lasting client type used. MQTTCLIENT_PERSISTENCE_NONE- use memory persistence. If the client device or system malfunction or run out off, the current status of any running message will be lost, even in QoS1 QoS2 and also some of the messages may not be delivered; MQTTCLIENT_PERSISTENCE_DEFAULT- use the default persistence mechanism (file system). Running status messages are stored in persistent storage, so as to provide some protection against loss of messages in the accident; MQTTCLIENT_PERSISTENCE_USER- using the procedure specified persistence implementation. Using this type of application can be controlled persistence mechanism, MQTTClient_persistence application must implement the interface.
persistence_context 如果应用程序使用的是MQTTCLIENT_PERSISTENCE_NONE持久化,该参数不使用,而且值应该设置为NULL。对于MQTTCLIENT_PERSISTENCE_DEFAULT持久化,应该设置持久化目录的位置(如果设置为NULL,则使用工作目录作为持久化目录)。使用MQTTCLIENT_PERSISTENCE_USER持久化,则将此参数指向有效的MQTTClient_persistence结构。

MQTTClient_setCallbacks

定义:

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

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

注意:在调用该函数时,MQTT客户端必须断开连接。(即先要调用该函数在连接客户端)。
| 参数 | 含义 |
| ---|-------------|
| handle | 指向MQTT客户端句柄的指针。句柄被成功从函数中返回的客户端引用所填充 |
| context| 指向任何应用程序特定上下文的指针。 上下文指针被传递给每个回调函数,以提供对回调中的上下文信息的访问。|
|cl|指向MQTTClient_connectionLost()回调函数的指针。 如果您的应用程序不处理断开连接,您可以将其设置为NULL。|
|ma|指向MQTTClient_messageArrived()回调函数的指针。 当您调用MQTTClient_setCallbacks()时,必须指定此回调函数。|
|dc|指向MQTTClient_deliveryComplete()回调函数的指针。 如果您的应用程序同步发布,或者您不想检查是否成功发送,则可以将其设置为NULL。|


MQTTClient_connect

定义:

DLLExport int MQTTClient_connect    (   
        MQTTClient      handle,
        MQTTClient_connectOptions *     options 
    )       

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

参数 含义
handle 指向MQTT客户端句柄的指针。句柄被成功从函数中返回的客户端引用所填充
options 指向有效的MQTTClient_connectOptions结构的指针。
> 返回值
0 连接成功
1 拒绝连接:不可接受的协议版本。
2 拒绝连接:标识符被拒绝。
3 拒绝连接:服务器不可用。
4 拒绝连接:用户名或密码错误。
5 拒绝连接:未经授权。
6 保留给未来用。

MQTTClient_subscribe

定义:

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

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

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

MQTTClient_publishMessage

definition:

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

Role: This feature attempts customers subscribe to a single theme, which may contain wildcards. This function also specifies the quality of service.

parameter meaning
handle A pointer to MQTT client handle. Successfully handle is returned from the client function reference filled
topicName Information-related topics.
msg MQTTClient_message pointer points to a valid configuration, which includes a payload and attributes of the message to be published
dt MQTTClient_deliveryToken pointer pointing. When the function returns successfully, dt will be assigned the token representative of the message. If no token passing procedure, which is set to NULL.

MQTTClient_waitForCompletion

definition:

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

Role: The client application calls this function to complete execution of the main thread of the message released synchronization. When invoked, MQTTClient_waitForCompletion () blocks execution until the message is successfully delivered or has exceeded a specified period of time.

parameter meaning
handle A pointer to MQTT client handle. Successfully handle is returned from the client function reference filled
dt MQTTClient_deliveryToken used to detect when the message was successfully delivered. The transfer token generated by the release function MQTTClient_publish () and MQTTClient_publishMessage ().
timeout The maximum number of milliseconds to wait.

Return Value:
message successfully delivered MQTTCLIENT_SUCCESS returns (0), if the time has expired or when the token detection problem, an error code is returned.


  Paho explain to the client to this end, if not understand, you can give me a message, to discuss together, progress together.

Guess you like

Origin www.cnblogs.com/zkwarrior/p/10954892.html