前词
由于前些天做的mqtt连接云平台项目测试过程中,发现了自身的代码在不良环境下,例如:网络断开、服务器断开的情况下,mqtt客户端无法感知连接已失效,仍然会继续向对端publish success。且在重新连接网络成功后,一下子重新往对端发送在连接失效的时间段内的发送数据,从而造成接收重复。
所以,自己去下载了mosquitto的源码,进行了系列分析。但是,由于本身能力有限,也不算很理解,如果有大哥是有了解的,还望私聊一起探索。
附上源码地址:https://github.com/eclipse/mosquitto
主要目录
主要需要关注的有/mosquitto/src、/mosquitto/lib、/mosquitto/client。
其中/src和/lib目录下主要放置服务端(Broker)的实现代码以及部分底层与网络相关的操作;client目录主要是订阅客户端和发布客户端的实现源码。
mosquitto_internal.h定义各种数据结构
mosquitto:外部调用接口
memory_mosq:内存分配处理,可记录内存用量
net_mosq:网络基础操作,tcp 创建,关闭等;打包/解包数据,向_mosquitto_packet 中写入/读取各种数据
send_mosq:主要实现发送请求逻辑(协议组包),实际命令请求实现组包
send_client_mosq:与 send_mosq 类似,主要实现客户端常用高频使用接口;
messages_mosq:主要针对消息的实现(PUBLISH,PUBACK,PUBREL…)
read_handle:处理收到的数据包,根据数据包类型做相应处理。
重要的数据结构
会话相关属性(上下文):主要用于保存客户端连接的所有信息,例如用户id,用户名,客户端socket,ip地址,密码,保持连接的时间值等
struct mosquitto {
mosq_sock_t sock;//mosquitto服务器程序与该客户端连接通信所用的socket描述符
#ifndef WITH_BROKER
mosq_sock_t sockpairR, sockpairW;// socket管道通知:非阻塞模式时,通知用,在mosquitto_loop 调用发送,
#endif
#if defined(__GLIBC__) && defined(WITH_ADNS)
struct gaicb *adns; /* For getaddrinfo_a */
#endif
enum mosquitto__protocol protocol;
char *address;//该客户端的IP地址
char *id;//该客户端登陆mosquitto程序时所提供的ID值,该值与其他的客户端不能重复
char *username;//username和password用于记录客户端登陆时所提供的用户名和密码
char *password;
uint16_t keepalive;//客户端需在此时间内向mosquitto服务器程序发送一条ping/pong消息
uint16_t last_mid;//最后一个消息id,发消息后++
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_all *will;
struct mosquitto__alias *aliases;
struct will_delay_list *will_delay_entry;
uint32_t maximum_packet_size;
int alias_count;
uint32_t will_delay_interval;
time_t will_delay_time;
#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;
bool ssl_ctx_defaults;
bool tls_ocsp_required;
char