1. 项目概述
在Web服务器开发中,客户端连接管理是一个核心问题。想象一下这样的场景:当大量客户端连接到服务器后,有些客户端可能会因为网络问题或程序崩溃而失去响应,但服务器却无法感知这种异常。这些"僵尸连接"会持续占用服务器资源,最终可能导致服务崩溃。这就是为什么我们需要一个可靠的连接超时管理机制。
TinyWebServer中的双向链表定时器模块,正是为解决这个问题而设计的。它通过一个精心构造的双向链表来管理所有客户端连接的定时器,按照超时时间排序,并利用Linux的信号机制定期检查超时情况。这种设计既保证了高效性,又确保了可靠性。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 核心数据结构解析
2.1 client_data结构体
这个结构体是连接信息的载体,相当于给每个客户端连接打上的"身份证"。它的定义如下:
cpp复制struct client_data {
sockaddr_in address; // 客户端socket地址
int sockfd; // 客户端连接的socket文件描述符
util_timer *timer; // 指向与此连接关联的定时器
};
在实际应用中,当一个新的客户端连接建立时,我们会创建一个client_data对象,填充其address和sockfd字段,然后为其创建一个对应的定时器,并将timer指针指向这个定时器。这种设计使得我们可以轻松地在定时器回调中获取到对应的连接信息。
提示:address字段保存了客户端的IP和端口信息,这在日志记录和调试时非常有用。
2.2 util_timer类
util_timer类是定时器系统的核心单元,相当于一个"倒计时沙漏"。它的完整定义如下:
cpp复制class util_timer {
public:
util_timer() : prev(NULL), next(NULL) {}
time_t expire; // 超时的绝对时间
void (*cb_func)(client_data *); // 触发超时调用的函数
client_data *user_data; // 回调函数参数
util_timer *prev; // 前驱指针
util_timer *next; // 后继指针
};
这里有几个关键点需要注意:
-
expire存储的是绝对时间戳,而不是相对时间。这是通过time(NULL)获取当前时间再加上超时时间间隔计算得到的。使用绝对时间戳可以避免因系统时间调整导致的问题。
-
cb_func是一个函数指针,指向超时发生时需要执行的回调函数。这种设计使得定时器逻辑与具体业务逻辑解耦,提高了代码的灵活性。
-
prev和next指针构成了双向链表的基础,这使得我们可以高效地进行插入和删除操作。
3. 定时器链表管理
3.1 sort_timer_lst类
sort_timer_lst类是整个定时器系统的"调度中心",它维护着一个按超时时间升序排列的双向链表。这种排序方式确保最早超时的定时器总是位于链表头部,这样在检查超时时只需从头部开始遍历,遇到第一个未超时的定时器就可以停止检查,大大提高了效率。
