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

相关推荐
2401_840192272 小时前
http状态码体系和相关经验汇总,给以后判断问题提供基础
网络·网络协议·http
余衫马2 小时前
为什么在 Windows 上用 Clang/LLVM?
c++·windows·c
小天源2 小时前
IP地址修改器
服务器·网络·tcp/ip
黄美美分享2 小时前
【音频编辑工具】跨平台轻量音频编辑器!音频剪辑工具!新手也能玩转专业处理
windows·安全·音视频
Godspeed Zhao2 小时前
现代智能汽车中的无线技术23——Wi-Fi(11)
网络·汽车·智能路由器
三两肉2 小时前
HTTP/2 特点解析,从 HTTP/1.1 的痛点到新一代协议的进化
网络·网络协议·http·http2
yuanmenghao2 小时前
车载Linux 系统问题定位方法论与实战系列 - OOM 与资源耗尽:系统是如何被“慢慢拖死”的
linux·运维·服务器·网络·驱动开发·自动驾驶
独行soc2 小时前
2026年渗透测试面试题总结-2(题目+回答)
android·java·网络·python·安全·web安全·渗透测试
爱学java的ptt2 小时前
AQS简单源码思路和手撕实现
java·网络