mosquitto2.0.15服务器主循环函数`mosquitto_main_loop`如何与客户端交互

本文详细分析了Mosquitto2.0.15版本的mosquitto_main_loop函数,该函数是MQTT代理服务器的核心,负责监听客户端消息并分发。文章介绍了函数的主要功能,包括监听客户端连接、处理MQTT消息、心跳维持、订阅管理等,并详细阐述了监听、接收连接、处理事件及不同消息类型的处理流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

mosquitto_main_loop 函数是 Mosquitto MQTT 代理服务器的核心函数之一,它用于监听来自客户端的消息,并将消息分发给订阅者。这个函数实现了 MQTT 协议的所有功能,包括消息发布和订阅、QoS质量等级、保留消息、持久化订阅、消息存储、安全认证等。可以说mosquitto_main_loop 函数支撑起了客户端从连接到销毁的整个生命周期的活动。对于开发人员而言,了解这个函数的源代码和原理是非常有帮助的。
本文基于mosquitto2.0.15源码,详细分析mosquitto服务器主循环函数mosquitto_main_loop与客户端交互的主要过程。
为了简化问题,我们分析时编译选项选择或设置文件参数设置基于下面的前提:
服务器运行在linux操作系统
采用支持更多客户端并发连接的epool机制
通信协议只支持MQTT协议
不包含SSL/TLS 安全认证支持
不支持服务器桥接

一、函数功能概述

mosquitto_main_loop函数是mosquitto2.0.15 MQTT代理服务器的主循环函数,它用于监听来自客户端的消息,并将消息分发给订阅者。
整个程序的入口函数是"main"函数,存放在src/mosquitto.c文件中,程序首先对命令行参数进行解析,然后进行MQTT代理的初始化和配置,包括权限控制、数据库的打开、安全模块的初始化等。接着程序调用mosquitto_main_loop函数进入主循环,函数定义如下:

int mosquitto_main_loop(struct mosquitto__listener_sock *listensock, int listensock_count)

函数的参数 listensock 是指向一个监听套接字结构体的指针,listensock_count 是监听套接字的数量。函数的主要功能是执行以下操作:

  1. 从监听套接字接收网络连接,并将连接分配给新的客户端。

  2. 从已连接的客户端读取MQTT消息。

  3. 对读取到的MQTT消息进行处理,包括解析消息头、分发消息、处理ACK等。

  4. 将需要发送的消息发送给对应的客户端。

  5. 处理客户端的PINGREQPINGRESP消息,保持心跳连接。

  6. 处理客户端的DISCONNECT消息,关闭连接并从客户端列表中删除。

  7. 处理客户端的WILL消息,将遗嘱消息发送给订阅者。

  8. 处理客户端的SUBSCRIBEUNSUBSCRIBE消息,更新客户端的订阅信息。

  9. 处理客户端的CONNECT消息,进行身份验证和会话管理。

  10. 处理客户端的PUBLISH消息,将消息发送给订阅者。

  11. 处理客户端的RESUME消息,恢复会话并发送缓存的消息。

  12. 处理客户端的AUTH消息,进行身份验证。

  13. 处理客户端的GETPUT消息,用于管理持久化订阅和消息存储。

  14. 处理客户端的PUBREL消息,确认QoS2的消息。

  15. 处理客户端的ACK消息,确认QoS1的消息。

函数会一直循环执行上述操作,直到程序接收到终止信号才会退出循环。如果在循环中出现错误,函数会返回错误码,并将错误信息输出到日志中。

二、与客户端交互主要流程

1.监听

...
int main(int argc, char *argv[])
{
   
   
...
	if(listeners__start()) return 1;
	rc = mux__init(listensock, listensock_count);
	if(rc) return rc;
...
	run = 1;
	rc = mosquitto_main_loop(listensock, listensock_count);
...
}

listensock_count 表示监听套接字的数量,数值在服务器启动前就确定了。通常情况下,由配置文件中监听端口的个数决定(严格的说,这个数量只包含监听打开成功的套接字数量),配置文件默认名称 mosquitto.conf ,文件位于 /etc/mosquitto/ 目录下。
监听程序开始在进入主循环之前。绑定监听后,调用mux__init函数,实际上是在调用 mux_epoll__init 函数,函数接收两个参数:

  • listensock 是一个指向 struct mosquitto__listener_sock 类型的指针,它指向一个存储有多个监听器信息的数组,每个元素都描述了一个监听器的 IP 地址、端口号等信息。
  • listensock_count 是一个整数,表示 listensock 数组中包含的监听器数量。

这个函数的功能是初始化一个 epoll 实例,并将所有监听器套接字添加到该实例中。这样,就可以在主循环中监听和处理来自客户端各种请求,同时,函数里面还初始化了一个存放事件struct epoll_event结构体数组,将数组每个成员的ptr指针关联到需要监听的struct mosquitto__listener_sock 结构对象,同时将这个对象的ident成员初始化为监听器–id_listener

源码中枚举定义了一个名为 struct_ident 的枚举类型,它包含四个枚举常量:

  1. id_invalid,值为 0,表示标识无效。
  2. id_listener,值为 1,表示标识是监听器(listener)。
  3. id_client,值为 2,表示标识是客户端(client)。
  4. id_listener_ws,值为 3,表示标识是 WebSocket 监听器。

这个枚举的作用是为 Mosquitto MQTT 代理服务器内部的各个对象和实体分配唯一的标识符,以便在代码中进行区分和操作。其中
id_invalid 可以用于表示一个未知的或未定义的标识符,而其他三个常量则分别表示 Mosquitto
服务器中三种不同类型的对象(监听器、客户端和 WebSocket 监听器)的标识符。

2.等待客户端事件

...
int mosquitto_main_loop(struct mosquitto__listener_sock *listensock, int listensock_count)
{
   
   
...
	while (run)
	{
   
   
	   ...
		rc = mux__handle(listensock, listensock_count);
		if (rc)
			return rc;
		...
	}
...
}

mosquitto_main_loop 函数核心是使用一个无限循环来处理客户端的连接,循环中调用了而mux__handle函数,而mux__handle又调用了mux_epoll__handle。mux_epoll__handle函数中调用 epoll_wait 函数等待事件发生。如果有事件发生,则对事件进行处理,如下所示。

...<
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值