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

基于信号的进程间通信程序信号投递异常排查求助

Minitalk 信号通信问题排查与修复

核心问题分析

你的程序存在信号丢失、字符串投递不完整的问题,主要源于以下几个逻辑错误:

  • 客户端位判断逻辑冗余:用byte > 0 && byte % 2 == 1判断发送位的方式不够直接,位运算更可靠;字节移位操作可以更规范。
  • 服务器信号标记未重置:signal_rec变量处理完信号后未清零,会导致重复处理旧信号值,引发逻辑混乱。
  • 服务器响应信号冲突:每个bit处理后发送SIGUSR1,字节完成时又额外发SIGUSR2,导致客户端收到重复确认信号,干扰等待逻辑。
  • 超时时间过短:9毫秒的超时窗口太窄,服务器可能因调度延迟来不及响应,触发误判。
  • 信号掩码未配置:处理信号时未阻塞同类信号,连续到达的信号可能被合并丢失。
  • 幂运算存在风险:_pow(2, bit_counter)可能触发整数溢出,位运算实现更安全高效。

修复后的代码片段

客户端(client.c)修改点

// 修正send_byte函数的位判断、超时时间和移位逻辑
void    send_byte(unsigned char byte, pid_t target)
{
    int count;
    int timeout;

    count = 0;
    while (count < 8)
    {
        timeout = 30000; // 延长超时到30毫秒,避免误判
        signal_rec = 0;
        // 用位运算直接判断最低位,逻辑更准确
        if (byte & 1)
            kill(target, SIGUSR1);
        else
            kill(target, SIGUSR2);
        while (signal_rec == 0 && timeout > 0)
        {
            usleep(100);
            timeout -= 100;
        }
        if (timeout == 0)
        {
            ft_printf("Server didn't response\n");
            exit(EXIT_FAILURE);
        }
        byte >>= 1; // 右移代替除法,更符合位操作逻辑
        count++;
    }
}

服务器(server.c)修改点

void    server_signal_handler(int signal_num, siginfo_t *sig_sender, void *ucont)
{
    (void)ucont;
    signal_rec = signal_num;
    if (sender_pid != sig_sender->si_pid)
    {
        sender_pid = sig_sender->si_pid;
        client_changed = 1;
    }
}

int main(void)
{
    struct  sigaction sa;
    unsigned char    byte;
    int     bit_counter;

    ft_printf("[PROCESS ID]: %d\n", getpid());
    client_changed = 0;
    sa.sa_sigaction = server_signal_handler;
    sa.sa_flags = SA_SIGINFO;
    // 阻塞SIGUSR1和SIGUSR2,防止处理信号时同类信号丢失
    sigemptyset(&sa.sa_mask);
    sigaddset(&sa.sa_mask, SIGUSR1);
    sigaddset(&sa.sa_mask, SIGUSR2);
    sigaction(SIGUSR1, &sa, NULL);
    sigaction(SIGUSR2, &sa, NULL);
    byte = 0;
    bit_counter = 0;
    while (1)
    {
        pause();
        if (client_changed == 1)
        {
            byte = 0;
            bit_counter = 0;
            client_changed = 0;
        }
        if (signal_rec == SIGUSR1)
            // 用位运算代替_pow,避免溢出风险
            byte |= (1 << bit_counter);
        bit_counter++;
        // 每处理一个bit就回复确认信号,统一逻辑
        kill(sender_pid, SIGUSR1);
        if (bit_counter == 8)
        {
            ft_printf("%c", byte);
            byte = 0;
            bit_counter = 0;
        }
        // 重置信号标记,避免重复处理旧信号
        signal_rec = 0;
    }
}

额外注意事项

  • 确保init_signal函数的信号配置与服务器一致,必须设置SA_SIGINFO标志和正确的信号掩码。
  • 测试时尽量避开高负载环境,防止进程调度延迟导致的信号响应延迟。
  • 可选优化:客户端发送完所有字节后,可等待服务器的最终确认信号,确保完整接收。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 05:53:18