Mosquitto源码学习

大家好,今天小白给大家简单介绍下Mosquitto,它是一个开源的MQTT broker,欢迎一起讨论学习。

Mosquitto 是一个开源的 MQTT broker ,目前支持 v3.1 和 v3.1.1 协议 ,同时提供了一个 C 语言动态链接库 libmosquitto ,用于实现 mqtt 客户端,源码地址:http://mosquitto.org/documentation/

1、主要的几个源码目录

源码目录层级比较多,但是需关注的目录有/mosquitto-1.5.8/src、/mosquitto-1.5.8/lib、/mosquitto-1.5.8/client三个目录,其中/src和/lib目录下主要放置服务端(Broker)的实现代码以及部分底层与网络相关的操作,client目录主要是订阅客户端和发布客户端的实现源码。

2、客户端

订阅客户端实现源码主要是在/client/sub_client.c文件中,main函数主要流程:

    a.调用client_config_load函数加载配置文件,初始化cfg变量以及命令行参数解析,cfg变量类型是struct mosq_config,客户端(订阅端和发布端)配置相关的变量。

    b. 调用client_id_generate函数,生成client id;id形如:mosqsub|pid-hostname。其中pid为该客户端进程的进程号,hostname是主机名。

    c. 调用mosquitto_new函数,为订阅客户端分配空间,返回一个客户端的操作句柄。

    d. 调用client_opts_set接口,根据cfg变量的标志位(will_topic,username,max_inflightprotocol_version等)去初始化客户端遗嘱相关项,用户名,密码,支持的协议版本等。

    e. 接下来就是给客户端绑定回调函数,即给客户端的函数指针成员变量(on_log,on_subscribe,    on_connect_with_flags, on_message)赋值。

    f. 然后调用client_connect函数,这个函数是用于初始化客户端host,port,keepalive,sockpairR,sockpairW,state等成员,并创建sock成员处理连接,以及在send__connect函数中组织连接请求的报文,并放到报文队列,然后依次发送出去。

   d. 最后就是进入到mosquitto_loop_forever函数,该函数是一个死循环,用于处理与服务端的数据交互。详细交互过程可以追踪源码。

发布客户端实现的源码主要是在/client/pub_client.c文件中,main函数主要流程:

  a. 同样的调用client_config_load函数,初始化cfg变量以及做命令行参数的解析。

  b. 初始化一些全局变量,供回调函数使用;如:topic,qos,retain,username,password等。

  c. 调用client_id_generate函数,生成发布客户端id。

  d. 调用mosquitto_new,为发布客户端分配空间,返回一个客户端的操作句柄。

  e. 接下来也是设置一些回调;

  f. 调用client_opts_set接口,同理目的是为了初始化发布客户端。

  g. 调用client_connect函数,同理处理连接相关操作。

  h. 最后是一个do while循环,处理与服务端交互相关的操作。

综上可以看出来,订阅客户端和发布客户端有部分操作是相似的,相同的处理逻辑放在:clinet.share.c中,阅读代码时可以对比理解。

3、服务端(broker,即代理)

服务端的实现逻辑主要是在/lib和/src目录下,main函数所在文件是:mosquitto.c,其大致流程是:

 a. 调用net__broker_init函数,创建套接字。

 b. 调用config__init函数,初始化服务端配置相关项。配置相关的结构体:struct mosquitto__config。

 c. 调用config__parse_args,根据配置文件和命令行参数初始化服务端配置。

 d. 调用db__open函数,主要是创建了订阅树。该变量是服务端最重要的结构体,维护了订阅树根节点,订阅客户端的索引,消息链表等。

 e. 调用mosquitto_security_module_init函数,给db中安全认证相关的成员变量初始化。

 f. 调用mosquitto_security_init,主要是函数指针调函数(上一步已经给函数指针赋值),实现安全认证相关的操作。

 g. 根据config.listener_count数目,循环调用net__socket_listen函数,在该函数中创建监听套接字,设置套接字属性,并开始监听。

 h. 接下来将所有config.listener[i]的套接字统一放到listensock数组中去管理;

 i. 调用drop_privileges函数,如果以root身份运行,此函数将尝试更改为非特权用户和组。

 j. 接下来是调用signal函数,为信号注册信号处理函数,实现消息的异步通知。

 k. 最后进入到mosquitto_main_loop函数,该函数的主要功能就是处理客户端的订阅以及发布等请求。

函数调用流程:

调用sysconf函数获取pollfd的最大值pollfd_max,病据此pollfds分配空间;

while大循环 中:

填充pollfds;

根据客户端套接字遍历哈希表,并返回查找到的客户端;

   db__message_write              //根据client的inflight_msgs消息的state进行相应的处理。

根据客户端id遍历哈希表,并返回查找到的客户端;

调用poll函数,获取准备好的描述符。
loop_handle_reads_writes
   HASH_ITER(遍历哈希表)
    packet__write
     net_write
      write

   packet__read        --->packet_mosq.c   
     handle__packet    --->/src/read_handle.c   (处理连接,订阅,发布等等)

4、总结

本篇主要是简单粗略的介绍了Mosquitto源码的中订阅客户端,发布客户端,服务端(broker,即代理)的源码调用流程,欢迎一起交流学习。

你可能感兴趣的:(Mosquitto源码学习)