基于信号的进程间通信程序信号投递异常排查求助
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
相关产品推荐
相关产品推荐

