MQTT 客户端源码分析
一、目录结构
首先我们还是来看一下 mosquitto-1.4.14 的源码目录结构
我们主要关注 client、lib、src 这三个目录。其中 src 和 lib 目录下主要放置 mosquitto 的实现代码以及部分底层与网络相关的操作,client 目录主要为两个客户端程序的实现源码。
我们主要就是来看看,这两个客户端的实现源码。
二、SUB 客户端源码
首先我们先看 sub_client.c
- struct mosq_config {
- char *id;
- char *id_prefix;
- int protocol_version;
- int keepalive;
- char *host;
- int port;
- int qos;
- bool retain;
- int pub_mode; /* pub */
- char *file_input; /* pub */
- char *message; /* pub */
- long msglen; /* pub */
- char *topic; /* pub */
- char *bind_address;
- #ifdef WITH_SRV
- bool use_srv;
- #endif
- bool debug;
- bool quiet;
- unsigned int max_inflight;
- char *username;
- char *password;
- char *will_topic;
- char *will_payload;
- long will_payloadlen;
- int will_qos;
- bool will_retain;
- #ifdef WITH_TLS
- char *cafile;
- char *capath;
- char *certfile;
- char *keyfile;
- char *ciphers;
- bool insecure;
- char *tls_version;
- # ifdef WITH_TLS_PSK
- char *psk;
- char *psk_identity;
- # endif
- #endif
- bool clean_session; /* sub */
- char **topics; /* sub */
- int topic_count; /* sub */
- bool no_retain; /* sub */
- char **filter_outs; /* sub */
- int filter_out_count; /* sub */
- bool verbose; /* sub */
- bool eol; /* sub */
- int msg_count; /* sub */
- #ifdef WITH_SOCKS
- char *socks5_host;
- int socks5_port;
- char *socks5_username;
- char *socks5_password;
- #endif
- };
- struct mosquitto {
- mosq_sock_t sock;
- #ifndef WITH_BROKER
- mosq_sock_t sockpairR, sockpairW;
- #endif
- #if defined(__GLIBC__) && defined(WITH_ADNS)
- struct gaicb *adns; /* For getaddrinfo_a */
- #endif
- enum _mosquitto_protocol protocol;
- char *address;
- char *id;
- char *username;
- char *password;
- uint16_t keepalive;
- uint16_t last_mid;
- enum mosquitto_client_state state;
- time_t last_msg_in;
- time_t next_msg_out;
- time_t ping_t;
- struct _mosquitto_packet in_packet;
- struct _mosquitto_packet *current_out_packet;
- struct _mosquitto_packet *out_packet;
- struct mosquitto_message *will;
- #ifdef WITH_TLS
- SSL *ssl;
- SSL_CTX *ssl_ctx;
- char *tls_cafile;
- char *tls_capath;
- char *tls_certfile;
- char *tls_keyfile;
- int (*tls_pw_callback)(char *buf, int size, int rwflag, void *userdata);
- char *tls_version;
- char *tls_ciphers;
- char *tls_psk;
- char *tls_psk_identity;
- int tls_cert_reqs;
- bool tls_insecure;
- #endif
- bool want_write;
- bool want_connect;
- #if defined(WITH_THREADING) && !defined(WITH_BROKER)
- pthread_mutex_t callback_mutex;
- pthread_mutex_t log_callback_mutex;
- pthread_mutex_t msgtime_mutex;
- pthread_mutex_t out_packet_mutex;
- pthread_mutex_t current_out_packet_mutex;
- pthread_mutex_t state_mutex;
- pthread_mutex_t in_message_mutex;
- pthread_mutex_t out_message_mutex;
- pthread_mutex_t mid_mutex;
- pthread_t thread_id;
- #endif
- bool clean_session;
- #ifdef WITH_BROKER
- bool is_dropping;
- bool is_bridge;
- struct _mqtt3_bridge *bridge;
- struct mosquitto_client_msg *msgs;
- struct mosquitto_client_msg *last_msg;
- int msg_count;
- int msg_count12;
- struct _mosquitto_acl_user *acl_list;
- struct _mqtt3_listener *listener;
- time_t disconnect_t;
- struct _mosquitto_packet *out_packet_last;
- struct _mosquitto_subhier **subs;
- int sub_count;
- int pollfd_index;
- # ifdef WITH_WEBSOCKETS
- # if defined(LWS_LIBRARY_VERSION_NUMBER)
- struct lws *wsi;
- # else
- struct libwebsocket_context *ws_context;
- struct libwebsocket *wsi;
- # endif
- # endif
- bool ws_want_write;
- #else
- # ifdef WITH_SOCKS
- char *socks5_host;
- int socks5_port;
- char *socks5_username;
- char *socks5_password;
- # endif
- void *userdata;
- bool in_callback;
- unsigned int message_retry;
- time_t last_retry_check;
- struct mosquitto_message_all *in_messages;
- struct mosquitto_message_all *in_messages_last;
- struct mosquitto_message_all *out_messages;
- struct mosquitto_message_all *out_messages_last;
- void (*on_connect)(struct mosquitto *, void *userdata, int rc);
- void (*on_disconnect)(struct mosquitto *, void *userdata, int rc);
- void (*on_publish)(struct mosquitto *, void *userdata, int mid);
- void (*on_message)(struct mosquitto *, void *userdata, const struct mosquitto_message *message);
- void (*on_subscribe)(struct mosquitto *, void *userdata, int mid, int qos_count, const int *granted_qos);
- void (*on_unsubscribe)(struct mosquitto *, void *userdata, int mid);
- void (*on_log)(struct mosquitto *, void *userdata, int level, const char *str);
- //void (*on_error)();
- char *host;
- int port;
- int in_queue_len;
- int out_queue_len;
- char *bind_address;
- unsigned int reconnect_delay;
- unsigned int reconnect_delay_max;
- bool reconnect_exponential_backoff;
- char threaded;
- struct _mosquitto_packet *out_packet_last;
- int inflight_messages;
- int max_inflight_messages;
- # ifdef WITH_SRV
- ares_channel achan;
- # endif
- #endif
- #ifdef WITH_BROKER
- UT_hash_handle hh_id;
- UT_hash_handle hh_sock;
- struct mosquitto *for_free_next;
- #endif
- };
client_config_load 客户端配置负载
- void init_config(struct mosq_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;
- }
- int mosquitto_lib_init(void)
- {
- #ifdef WIN32
- srand(GetTickCount());
- #else
- struct timeval tv;
- gettimeofday(&tv, NULL);
- srand(tv.tv_sec*1000 + tv.tv_usec/1000);
- #endif
- _mosquitto_net_init();
- return MOSQ_ERR_SUCCESS;
- }
这里有个时间戳函数 gettimeofday,参看:C语言再学习 -- 时间函数
client_id_generate 生成客户端 ID
- 1502159601: New client connected from 127.0.0.1 as mosqsub|2431-ubuntu (c1, k60)
看了一下这个函数里面就是一些初始化的东西
- {
- char err[1024];
- int rc;
- #ifdef WITH_SRV
- if(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);
- }
- #else
- rc = mosquitto_connect_bind(mosq, cfg->host, cfg->port, cfg->keepalive, cfg->bind_address);
- #endif
- if(rc>0){
- if(!cfg->quiet){
- if(rc == MOSQ_ERR_ERRNO){
- #ifndef WIN32
- strerror_r(errno, err, 1024);
- #else
- FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, errno, 0, (LPTSTR)&err, 1024, NULL);
- #endif
- fprintf(stderr, "Error: %s\n", err);
- }else{
- fprintf(stderr, "Unable to connect (%s).\n", mosquitto_strerror(rc));
- }
- }
- mosquitto_lib_cleanup();
- return rc;
- }
- return MOSQ_ERR_SUCCESS;
- }
可以看到里面又有几个重要函数
mosquitto_connect_bind --> _mosquitto_connect_init
三、PUB 客户端源码
client_id_generate 生成客户端 ID

1.将RETAIN标志位置为1,可使新的订阅者收到之前保持的或上一个确定有效的消息。
2.区分新订阅者(RETAIN标志为1)和老订阅者(RETAIN标志为0)
MQTT 客户端源码分析的更多相关文章
- MQTT再学习 -- MQTT 客户端源码分析
MQTT 源码分析,搜索了一下发现网络上讲的很少,多是逍遥子的那几篇. 参看:逍遥子_mosquitto源码分析系列 参看:MQTT libmosquitto源码分析 参看:Mosquitto学习笔记 ...
- Eureka 系列(04)客户端源码分析
Eureka 系列(04)客户端源码分析 [TOC] 0. Spring Cloud 系列目录 - Eureka 篇 在上一篇 Eureka 系列(01)最简使用姿态 中对 Eureka 的简单用法做 ...
- TeamTalk源码分析(十一) —— pc客户端源码分析
--写在前面的话 在要不要写这篇文章的纠结中挣扎了好久,就我个人而已,我接触windows编程,已经六七个年头了,尤其是在我读研的三年内,基本心思都是花在学习和研究windows程序上 ...
- SSO单点登录系列1:cas客户端源码分析cas-client-java-2.1.1.jar
落雨 cas 单点登录 希望能给以后来研究cas的兄弟留下一点思路,也算是研究了两天的成果,外国人的代码写的很晦涩,翻译下来也没有时间继续跟进,所以有错误的还请大家跟帖和我讨论,qq 39426378 ...
- dubbo客户端源码分析(一)
rpc框架有很多,公司自研.开源的thrift.dubbo.grpc等.我用过几个框架,了解了一下实现原理,客户端基本都是用代理实现,jdk动态代理.cglib等.最近一段时间想了解一下dubbo源码 ...
- Tars-Java客户端源码分析
一.基本RPC框架简介 在分布式计算中,远程过程调用(Remote Procedure Call,缩写 RPC)允许运行于一台计算机的程序调用另一个地址空间计算机的程序,就像调用本地程序一样,无需额外 ...
- Android之开源中国客户端源码分析(二)
1. 加载动画圈实现 <ProgressBar android:id="@+id/main_head_progress" style="@style/loading ...
- Android之开源中国客户端源码分析(一)
程序启动第一个界面类: net.oschina.app.AppStart功能描述:一张图片代码细节描述:一个透明度的动画效果,效果动画完成后自动启动新的Activity(Main) 基本BaseAct ...
- AndroidPn源码分析(二)
接上篇: (一)客户端与服务器建立连接 上一篇写到ClientSession createClientSession这里,创建一个客户端的session.在SessionManager类中创建了ses ...
随机推荐
- spring中bean的作用域属性single与prototype的区别
https://blog.csdn.net/linwei_1029/article/details/18408363
- JAVA使用并行流(ParallelStream)时要注意的一些问题
https://blog.csdn.net/xuxiaoyinliu/article/details/73040808
- cocos2d-x AssetsManager libcurl使用心得
libcurl使用心得 最新正在写cocosclient更新的逻辑.研究了一下cocos2d-x自带的Libcurl,下面是自己在使用过程中的心得和遇到的未解问题.希望大家一起讨论一下,欢迎大家指导. ...
- __str__ 和 __unicode__ 的区别和用法
转自:https://www.cnblogs.com/painberg/p/8514860.html 简而言之,就是__str__和__unicode__都是为了再管理站点中加载这个表时想显示什么属性 ...
- c++编码习惯
1 大驼峰命名法 类名和函数名由单词构成,每个单词的首字母大写. 2 函数命名 大驼峰命名法. 3 类命名 大驼峰命名,但是为了和函数名区分开,在前面加上一个大写的C.
- linux批量更改权限
用命令 sudo chmod 777 -Rfv /home/name/* 注释:1.777 为 要修改成 的 文件的 权限:2.-R 是 子目录 下的 文件 也修改:3.-f 强制:4. -v是 显示 ...
- 【Java 语言生态篇】Junit 测试单元
01 概述 JUnit是一个由 Erich Gamma 和 Kent Beck 编写的一个回归测试框架(regression testing framework).Junit测试是白盒测试.JUn ...
- vue.use解析
vue.use源码: Vue.use = function (plugin) { /*判断插件是否已引入*/ if (plugin.installed) { return } //倒序为一个数组[] ...
- 20145239杜文超 《Java程序设计》第3周学习总结
20145239 <Java程序设计>第3周学习总结 教材学习内容总结 一.第四章: (1)对象和类: 使用Java撰写程序几乎都在使用对象,要产生对象必须先定义类,类是对象的设计图,对象 ...
- ES索引瘦身 禁用_source后需要设置field store才能获取数据 否则无法显示搜索结果
在默认情况下,开启_all和_source 这样索引下来,占用空间很大. 根据我们单位的情况,我觉得可以将需要的字段保存在_all中,然后使用IK分词以备查询,其余的字段,则不存储. 并且禁用_sou ...