MQTT源码分析,搜索了一下发现网络上讲的很少,多是逍遥子的那几篇。
参看:逍遥子_mosquitto源码分析系列
参看:MQTTlibmosquitto源码分析
参看:Mosquitto学习笔记
一、目录结构首先我们还是来看一下mosquitto-1.4.14的源码目录结构
我们主要就是来看看,这两个客户端的实现源码。
二、SUB客户端源码
首先我们先看sub_client.c我们从main函数开始。
查看结构体:结构体structmosq_config主要为MQTT的配置信息structmosq_config{char*id;char*id_prefix;intprotocol_version;intkeepalive;char*host;intport;intqos;boolretain;intpub_mode;/*pub*/char*file_input;/*pub*/char*message;/*pub*/longmsglen;/*pub*/char*topic;/*pub*/char*bind_address;#ifdefWITH_SRVbooluse_srv;#endifbooldebug;boolquiet;unsignedintmax_inflight;char*username;char*password;char*will_topic;char*will_payload;longwill_payloadlen;intwill_qos;boolwill_retain;#ifdefWITH_TLSchar*cafile;char*capath;char*certfile;char*keyfile;char*ciphers;boolinsecure;char*tls_version;#ifdefWITH_TLS_PSKchar*psk;char*psk_identity;#endif#endifboolclean_session;/*sub*/char**topics;/*sub*/inttopic_count;/*sub*/boolno_retain;/*sub*/char**filter_outs;/*sub*/intfilter_out_count;/*sub*/boolverbose;/*sub*/booleol;/*sub*/intmsg_count;/*sub*/#ifdefWITH_SOCKSchar*socks5_host;intsocks5_port;char*socks5_username;char*socks5_password;#endif};
client_config_load客户端配置负载第二个参数,可选择选择是PUB还是SUB
然后看到init_config函数
可以看到一些初始化配置voidinit_config(structmosq_config*cfg){memset(cfg,0,sizeof(*cfg));cfg->port=1883;cfg->max_inflight=20;cfg->keepalive=60;cfg->clean_session=true;cfg->eol=true;cfg->protocol_version=MQTT_PROTOCOL_V31;}
mosquitto_lib_init初始化(重点)
client_id_generate生成客户端ID其实就是我们讲MQTT服务器的时候,订阅主题然后在服务器上多出的那一行信息。里面的mosqsub|2431-ubuntu就是客户端ID。这个函数就是干这个。1502159601:Newclientconnectedfrom127.0.0.1asmosqsub|2431-ubuntu(c1,k60)
mosquitto_new新建一个mosq。(重点)
看了一下这个函数里面就是一些初始化的东西然后可以看到它也是在lib目录下定义的。所以说需要链接动态库libmosquitto.so.1。其他不用改。
client_ipts_set各种设置。懒得看...
一些调试信息以及订阅回调设置mosquitto_subscribe_callback_set(重要)
连接回调设置,和信息回调设置(重点)
这两个函数都是在lib目录下定义的。里面都是有互斥锁的。
client_connect客户端连接
intclient_connect(structmosquitto*mosq,structmosq_config*cfg){charerr[1024];intrc;#ifdefWITH_SRVif(cfg->use_srv){rc=mosquitto_connect_srv(mosq,cfg->host,cfg->keepalive,cfg->bind_address);}else{rc=mosquitto_connect_bind(mosq,cfg->host,cfg->port,cfg->keepalive,cfg->bind_address);}#elserc=mosquitto_connect_bind(mosq,cfg->host,cfg->port,cfg->keepalive,cfg->bind_address);#endifif(rc>0){if(!cfg->quiet){if(rc==MOSQ_ERR_ERRNO){#ifndefWIN32strerror_r(errno,err,1024);#elseFormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,NULL,errno,0,(LPTSTR)&err,1024,NULL);#endiffprintf(stderr,"Error:%s\n",err);}else{fprintf(stderr,"Unabletoconnect(%s).\n",mosquitto_strerror(rc));}}mosquitto_lib_cleanup();returnrc;}returnMOSQ_ERR_SUCCESS;}可以看到里面又有几个重要函数mosquitto_connect_srvmosquitto_connect_bind-->_mosquitto_connect_init
然后不断回环,里面的参数自己看。
最后是mosq的销毁和库的关闭。(重点)
到此结束!!三、PUB客户端源码接下来来看pub_client.c有一些相同部分我就不再重复了。
一些配置信息的比较
client_id_generate生成客户端ID
调试信息这里面就没有了订阅回调设置mosquitto_subscribe_callback_set
然后这里看这里,是有区别的。(重点)
connect、disconnect、publish.这些回调设置
回环开始、结束
最重要的来了,dowhile循环里的发布内容(重点)
这里的qos就是消息发布服务质量级别。
然后还有retain用于区分新老订阅者RETAIN标志位只用于PUBLISH消息,当服务器收到某个主题的PUBLISH消息时,如果RETAIN标志位为1,则表示服务在将该消息发送给所有的已订阅该主题的订阅者后(发送前服务器将RETAIN标志置为0),还需保持这条消息,当有新增的订阅者时,再将这条消息发给新增的订阅者;如果RETAIN标志位为0,则不保持消息,也不用发给新增的订阅者。目的:1.将RETAIN标志位置为1,可使新的订阅者收到之前保持的或上一个确定有效的消息。2.区分新订阅者(RETAIN标志为1)和老订阅者(RETAIN标志为0)