SIGALRM信号处理机制详解
1. 信号处理流程
cpp
// 信号处理函数
void Utils::sig_handler(int sig)
{
// 为保证函数的可重入性,保留原来的errno
int save_errno = errno;
int msg = sig;
send(u_pipefd[1], (char *)&msg, 1, 0);
errno = save_errno;
}
当SIGALRM信号发生时:
- 保存errno:保证信号处理函数的可重入性
- 发送信号到管道:将信号编号通过管道发送给主线程
- 恢复errno:恢复原来的错误状态
2. 定时器处理核心
cpp
// 定时处理任务,重新定时以不断触发SIGALRM信号
void Utils::timer_handler()
{
LOG_INFO << "in timer_handler: call m_timer_list.tick(): ";
m_timer_list.tick();
alarm(m_TIMESLOT);
}
3. 定时器链表处理
cpp
void sort_timer_list::tick() // 定时任务处理函数
{
LOG_TRACE << "tick: head " << head;
if (!head)
{
return;
}
time_t cur = time(NULL);
util_timer *tmp = head;
while (tmp)
{
if (cur < tmp->expire) // cur当前时间小于定时器的过期时间,说明后面的定时器也没有到期
{
break;
}
LOG_INFO << "while(tmp): tmp user_data->sockfd: " << tmp->user_data->sockfd;
tmp->cb_func(tmp->user_data);
head = tmp->next;
if (head)
{
head->prev = NULL;
}
delete tmp;
tmp = head;
}
}
4. 回调函数处理超时连接
cpp
void cb_func(client_data *user_data)
{
LOG_INFO << "user_data: " << user_data->sockfd;
LOG_INFO << " epoll_ctl(Utils::u_epollfd, EPOLL_CTL_DEL, user_data->sockfd, 0)";
epoll_ctl(Utils::u_epollfd, EPOLL_CTL_DEL, user_data->sockfd, 0);
assert(user_data);
close(user_data->sockfd);
http_conn::m_user_count--;
LOG_INFO << "http_conn::m_user_count: " << http_conn::m_user_count;
}
完整的事件处理流程
1. 信号设置
utils.addsig(SIGALRM, utils.sig_handler, false);
- SIGALRM:定时器信号,用于周期性触发
- utils.sig_handler:自定义信号处理函数
- false:不自动重启被中断的系统调用
2. 定时器初始化
每个新连接建立时创建定时器:
time_t cur = time(nullptr);
timer->expire = cur + 3 * TIMESLOT; // 设置3倍时间片后过期
utils.m_timer_list.add_timer(timer);
3. 周期性处理
- SIGALRM信号触发 →
utils.sig_handler - 信号通过管道传递 → 主线程epoll监听到管道可读
- 调用
utils.timer_handler()→ 处理超时连接 - 重新设置alarm → 继续周期性触发
4. 主要功能
🔍 连接超时检测
- 检测空闲或异常连接
- 防止资源泄漏
🧹 资源回收
- 关闭超时连接的文件描述符
- 从epoll实例中移除监控
- 更新用户连接计数
⚡ 心跳机制
- 周期性检查连接状态
- 确保服务器稳定性
5. 关键参数
- m_TIMESLOT:定时器时间间隔(秒)
- 3 * TIMESLOT:连接超时时间
- restart=false:不自动重启系统调用,确保定时器精确性
总结
utils.addsig(SIGALRM, utils.sig_handler, false);实现了Web服务器的连接超时管理机制,通过周期性SIGALRM信号触发定时器检查,自动清理超时连接,是保证服务器稳定性和资源有效利用的关键组件。
SIGTERM信号处理详解
🔍 信号作用
SIGTERM(信号编号15)是终止进程信号,用于在类Unix操作系统中请求一个进程优雅地终止。
📋 处理机制
从代码中可以看到完整的处理流程:
cpp
// 信号处理函数
case SIGTERM: // SIGTERM是一种信号,用于在类 Unix 操作系统中请求一个进程终止
stop_server = true;
break;
🔄 完整处理流程
-
信号注册:
utils.addsig(SIGTERM, utils.sig_handler, false); -
信号传递:
- 当收到SIGTERM信号时,
utils.sig_handler函数被调用 - 信号通过管道发送给主线程:
send(u_pipefd[1], (char *)&msg, 1, 0)
- 当收到SIGTERM信号时,
-
主线程处理:
cppbool WebServer::dealwithsignal(bool &timeout, bool &stop_server) { // 从管道读取信号 ret = recv(m_pipefd[0], signals, sizeof(signals), 0); switch (signals[i]) { case SIGTERM: stop_server = true; // 设置停止服务器标志 break; } } -
服务器停止:
- 在
eventLoop中检查stop_server标志 - 当
stop_server为true时,退出事件循环,优雅关闭服务器
- 在
🎯 主要用途
优雅关闭服务器
- 允许服务器完成当前请求处理
- 清理资源(关闭连接、释放内存)
- 记录日志信息
与SIGKILL的区别
- SIGTERM:允许程序进行清理工作后终止
- SIGKILL:立即强制终止,无法被捕获或忽略
⚡ 触发方式
在Linux系统中可以通过以下命令发送SIGTERM信号:
kill -TERM <进程ID>
# 或简写
kill <进程ID>
🔧 配置参数
- SIGTERM:终止进程信号(编号15)
- utils.sig_handler:自定义信号处理函数
- false:不自动重启被中断的系统调用
📊 与其他信号的对比
| 信号 | 编号 | 作用 | 处理方式 |
|---|---|---|---|
| SIGTERM | 15 | 优雅终止进程 | 允许清理资源 |
| SIGALRM | 14 | 定时器信号 | 处理超时连接 |
| SIGPIPE | 13 | 管道破裂 | 忽略,防止崩溃 |
总结
utils.addsig(SIGTERM, utils.sig_handler, false);实现了Web服务器的优雅关闭机制,当收到SIGTERM信号时,服务器会设置停止标志,在完成当前请求处理后安全退出,确保资源正确释放,是服务器稳定运行的重要保障。