SIGALRM信号处理机制详解

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信号发生时:

  1. 保存errno:保证信号处理函数的可重入性
  2. 发送信号到管道:将信号编号通过管道发送给主线程
  3. 恢复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. 周期性处理

  1. SIGALRM信号触发 → utils.sig_handler
  2. 信号通过管道传递 → 主线程epoll监听到管道可读
  3. 调用utils.timer_handler() → 处理超时连接
  4. 重新设置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;

🔄 完整处理流程

  1. 信号注册:

    复制代码
    utils.addsig(SIGTERM, utils.sig_handler, false);
  2. 信号传递:

    • 当收到SIGTERM信号时,utils.sig_handler函数被调用
    • 信号通过管道发送给主线程:send(u_pipefd[1], (char *)&msg, 1, 0)
  3. 主线程处理:

    cpp 复制代码
    bool 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;
        }
    }
  4. 服务器停止:

    • 在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信号时,服务器会设置停止标志,在完成当前请求处理后安全退出,确保资源正确释放,是服务器稳定运行的重要保障。

相关推荐
AI日报派送佬4 小时前
2026年10月14日AI行业日报|Gemini 4 Argon正式发布;小模型跨设备传播风险引发安全热议
网络·人工智能·openai·谷歌·deepseek·anthropic·ai日报
安易算力5 小时前
昇腾CANN算子开发与MindSpore部署调优实践:从Ascend C到模型推理全链路
网络·架构
遇印记6 小时前
传输层,网络层
运维·服务器·网络·windows·学习
北京中科新远科技7 小时前
高速光模块上线验收实战:DOM、FEC、BER与端口计数器怎么一起看
服务器·网络·php
又見山7 小时前
Obsidian 跨平台同步实测:Nutstore Sync 在 Windows、Mac、Linux、iOS、Android 全平台综合测评
windows·macos·obsidian·obsidian同步·obsidian教程·obsidian入门·obsidian笔记库搭建
jearry9 小时前
一个编辑器两个内核:Markdown 实时视图与源码视图并存时的竞态、光标锚点与 PDF 导出
windows·markdown
80s7779 小时前
动态IP是什么,动态IP的应用场景有哪些?
网络·网络协议·tcp/ip
逆向编程9 小时前
DirectX修复工具下载安装教程-Windows系统DLL缺失检测修复完整图文步骤
windows
钱栈up10 小时前
电脑卡死7分钟,日志断在13:56:03:一次Windows硬挂死的根因复盘
windows