You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C语言用SIGUSR1/SIGUSR2实现的服务端客户端程序通信异常求助

minitalk信号传输异常问题排查与修复

核心故障原因

  • 信号竞态丢失:客户端调用kill()发送信号后,服务端的响应信号可能在客户端执行pause()之前就已经送达,此时信号处理函数执行完成后才会走到pause(),客户端会永远阻塞,消息越长触发该问题的概率越高,完全符合你描述的故障现象。
  • 客户端sigaction未初始化完整:客户端定义的c_signal结构体只赋值了sa_handler,其余字段(sa_mask、sa_flags)为栈上随机值,会导致信号处理逻辑不稳定。
  • (可选优化)服务端在信号处理函数中调用usleep(300)完全多余,反而会增加传输耗时和异常概率。

修复方案

客户端修改

  1. 初始化sigaction结构体时清空所有字段,设置合理的信号掩码:
// main函数中sigaction初始化部分修改为:
g_info = (s_info *)malloc(sizeof(s_info));
memset(&c_signal, 0, sizeof(c_signal)); // 清空结构体,避免随机值
c_signal.sa_handler = sig_handler;
sigemptyset(&c_signal.sa_mask);
sigaddset(&c_signal.sa_mask, SIGUSR1);
sigaddset(&c_signal.sa_mask, SIGUSR2); // 处理信号时阻塞另一路信号,避免嵌套干扰
sigaction(SIGUSR1, &c_signal, NULL);
sigaction(SIGUSR2, &c_signal, NULL);
  1. 解决信号竞态问题:添加全局标志位标记是否收到响应,发信号前先重置标志位,循环检查标志位结合pause避免丢信号:
    首先在头文件s_info结构体中新增字段:
typedef struct t_info
{
    // 原有字段保留,新增如下字段
    int ack_received;
} s_info;

修改信号处理函数:

void    sig_handler(int signum)
{
    if (signum == g_info->cur_sig)
        g_info->ack_received = 1;
    else
    {
        write (1, "signal interrupt\n", 17);
        exit(0);
    }
}

修改send_int和send_string中发送信号的逻辑,每次发信号前重置标志位,把原有的单条pause()替换为循环检查:

// 每次kill发送信号前新增一行
g_info->ack_received = 0;
// 把原来的pause()替换为
while(!g_info->ack_received) pause();

服务端修改

  1. 移除信号处理函数中的usleep(300),无任何作用反而拖慢速度。
  2. (可选)不需要在sigaction的sa_mask中阻塞SIGUSR1和SIGUSR2,信号处理函数执行时默认会阻塞当前触发的信号,足够使用。

验证

修改完成后重新编译,长文本传输成功率会达到100%,不会再出现服务端无输出的问题。

内容的提问来源于stack exchange,提问作者acho

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 05:36:05