mqttcclient实现消息推送入门指南Word格式文档下载.docx
《mqttcclient实现消息推送入门指南Word格式文档下载.docx》由会员分享,可在线阅读,更多相关《mqttcclient实现消息推送入门指南Word格式文档下载.docx(9页珍藏版)》请在冰豆网上搜索。
服务端推送消息,也是基于主题的。
当服务器发现有主题(如,topic=“天气”)时,就会给所有订阅该主题的客户端推送payload内容。
这里需要个前提,就是有客户端订阅topic=”天气”这个主题;
一旦客户端订阅该主题,服务端就会每收到该主题的消息,都会推送给订阅该主题的客户端。
如果客户端不需要关注该主题了,也就是说不想接受到这样的推送消息了,只要取消otpic=”天气”的主题订阅即可。
MQTT协议是为大量计算能力有限,且工作在低带宽、不可靠的网络的远程传感器和控制设备通讯而设计的协议,它具有以下主要的几项特性:
使用发布/订阅消息模式,提供一对多的消息发布,解除应用程序耦合;
对负载内容屏蔽的消息传输;
使用TCP/IP提供网络连接;
有三种消息发布服务质量:
“至多一次”,消息发布完全依赖底层TCP/IP网络。
会发生消息丢失或重复。
这一级别可用于如下情况,环境传感器数据,丢失一次读记录无所谓,因为不久后还会有第二次发送。
“至少一次”,确保消息到达,但消息重复可能会发生。
“只有一次”,确保消息到达一次。
这一级别可用于如下情况,在计费系统中,消息重复或丢失会导致不正确的结果。
(在实际编程中,只需要设置QoS值即可实现以上几种不同消息发布服务质量模式)
小型传输,开销很小(固定长度的头部是2字节),协议交换最小化,以降低网络流量;
使用LastWill和Testament特性通知有关各方客户端异常中断的机制;
生成dll库?
混合编程?
在开始开发之前需要做一些准备工作,MQTT已经把所有的APIs封装好了,我们可以使用它的dll库,也可以直接导入源码进行混合编程,一般要求不高的话(因为不太懂得话,最好不要修改源码)可以直接将源码生成dll,然后使用即可,下文就是使用该方式:
gitclone
从这里获得CClient源码之后,可以直接使用VS打开(我是VS2013):
对于上图的说明,下载源码后,打开将是以上界面,包括十来个工程,这里讲解几个:
paho-mqtt3a:
一般实际开发中就是使用这个,a表示的是异步消息推送(asynchronous)。
paho-mqtt3as:
as表示的是异步+加密(asynchronous+OpenSSL)。
paho-mqtt3c:
c表示的应该是同步(Synchronize),一般性能较差,是发送+等待模式。
paho-mqtt3cs:
同上,增加了一个OpenSSL而已。
这里根据自身的需要选择不同的项目生成DLL即可,右击单个项目->
生成。
由于你电脑中可能没有OPenSSL环境,如果点击VS工具栏中的生成解决方案,十有八九会失败,因为它会生成所有项目的解决方案,其实你根本用不着这么多。
另外,上图中无法打开包括文件VersionInfo.h,你只需要在src文件夹中找到VersionInfo.h.in文件,去掉.in后缀->
重新生成即可。
了解更多可以阅读《MQTTCClientforPosixandWindows》一文,下面根据官网资料,摘录了几个C语言实现MQTT的小DEMO。
MQTT使用起来也十分容易,基本上就那四五个函数:
MQTTClient_create(创建客户端)、MQTTClient_connect(连接服务端)、MQTTClient_publishMessage(客户端->
服务端发送消息)、MQTTClient_subscribe(客户端订阅某个主题)等等。
其中,很多异步回调函数,需要自己去实现,如,
MQTTAsync_setCallbacks(mqtt->
_client,mqtt->
_client,connlost,msgarrvd,NULL);
1
MQTTAsync_setCallbacks中,
connlost函数指针,是当MQTT意外断开链接时会回调的函数,由自己实现;
msgarrvd函数指针,是当服务器有消息推送回来时,客户端在此处接受服务端消息内容。
另外,就是一些函数执行是否成功的回调函数,C语言封装回调之后,就是这么写法,看起来有些变扭。
有兴趣的可以看《浅谈C/C++回调函数(Callback)&
函数指针》文章,再了解以下回调函数。
mqtt->
_conn_opts.onSuccess=onConnect;
_conn_opts.onFailure=onConnectFailure;
12
最后,不得不说的就是,MQTT有些发送或者是订阅的内容时(某些函数中),在编程最好将参数中传进来的值在内存中拷贝一份再操作,笔者当时开发时,就是因为这样的问题,折腾了较长时间,后来在wireshark中发现数据包中根本没有内容,才知道是由于函数参数是指针形式,直接在异步中使用可能会发生一些未知的错误。
#include"
stdio.h"
stdlib.h"
string.h"
MQTTClient.h"
#defineADDRESS"
tcp:
//localhost:
1883"
#defineCLIENTID"
ExampleClientPub"
#defineTOPIC"
MQTTExamples"
#definePAYLOAD"
HelloWorld!
"
#defineQOS1
#defineTIMEOUT10000L
intmain(intargc,char*argv[])
{
MQTTClientclient;
MQTTClient_connectOptionsconn_opts=MQTTClient_connectOptions_initializer;
MQTTClient_messagepubmsg=MQTTClient_message_initializer;
MQTTClient_deliveryTokentoken;
intrc;
MQTTClient_create(&
client,ADDRESS,CLIENTID,
MQTTCLIENT_PERSISTENCE_NONE,NULL);
conn_opts.keepAliveInterval=20;
conn_opts.cleansession=1;
if((rc=MQTTClient_connect(client,&
conn_opts))!
=MQTTCLIENT_SUCCESS)
{
printf("
Failedtoconnect,returncode%d\n"
rc);
exit(EXIT_FAILURE);
}
pubmsg.payload=PAYLOAD;
pubmsg.payloadlen=strlen(PAYLOAD);
pubmsg.qos=QOS;
pubmsg.retained=0;
MQTTClient_publishMessage(client,TOPIC,&
pubmsg,&
token);
Waitingforupto%dsecondsforpublicationof%s\n"
"
ontopic%sforclientwithClientID:
%s\n"
(int)(TIMEOUT/1000),PAYLOAD,TOPIC,CLIENTID);
rc=MQTTClient_waitForCompletion(client,token,TIMEOUT);
Messagewithdeliverytoken%ddelivered\n"
token);
MQTTClient_disconnect(client,10000);
MQTTClient_destroy(&
client);
returnrc;
}12345678910111213141516171819202122232425262728293031323334353637383940
volatileMQTTClient_deliveryTokendeliveredtoken;
voiddelivered(void*context,MQTTClient_deliveryTokendt)
Messagewithtokenvalue%ddeliveryconfirmed\n"
dt);
deliveredtoken=dt;
}
intmsgarrvd(void*context,char*topicName,inttopicLen,MQTTClient_message*message)
inti;
char*payloadptr;
Messagearrived\n"
);
topic:
topicName);
message:
payloadptr=message->
payload;
for(i=0;
ipayloadlen;
i++)
putchar(*payloadptr++);
putchar('
\n'
MQTTClient_freeMessage(&
message);
MQTTClient_free(topicName);
return1;
voidconnlost(void*context,char*cause)
\nConnectionlost\n"
cause:
cause);
MQTTClient_setCallbacks(client,NULL,connlost,msgarrvd,delivered);
deliveredtoken=0;
Waitingforpublicationof%s\n"
PAYLOAD,TOPIC,CLIENTID);
while(deliveredtoken!
=token);
}123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
Asynchronoussubscriptionexample
ExampleClientSub"
intch;
Subscribingtotopic%s\nforclient%susingQoS%d\n\n"
PressQtoquit\n\n"
TOPIC,CLIENTID,QOS);
MQTTClient_subscribe(client,TOPIC,QOS);
do
ch=getchar();
}while(ch!
='
Q'
&
&
ch!
='
q'
}1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465