使用SIGUSR1、SIGUSR2传输二进制数据时接收异常如何解决
问题根因
- 服务端仅调用1次
pause(),只能捕获单次信号,收到第一个信号后程序停止等待,剩余6个bit的信号无法被接收 - 信号默认不支持排队,相同信号连续发送时会被合并丢弃,客户端无同步直接连发7个信号大概率会丢失中间信号
printf是不可重入函数,在信号处理函数内直接调用可能触发未知异常- 收发双方没有同步机制,发送节奏不匹配进一步加剧信号丢失
修复方案
服务端修改逻辑
- 新增循环等待逻辑,直到收满单个字符对应的7位二进制位再停止
- 使用
volatile sig_atomic_t类型的原子变量存储信号传递的bit数据,避免读写过程被信号打断出现数据错误 - 将打印操作移出信号处理函数,收满所有bit后统一输出
- 每处理完一个bit向客户端发送确认信号,通知客户端可以发送下一个bit
服务端示例代码:
#include <signal.h> #include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <stdlib.h> volatile sig_atomic_t current_bit; volatile sig_atomic_t bit_received = 0; void my_handler(int signum) { if (signum == SIGUSR1) { current_bit = 1; } else if (signum == SIGUSR2) { current_bit = 0; } bit_received = 1; } int main(int argc, char *argv[]) { int bit_cnt = 0; char res[8] = {0}; pid_t client_pid = atoi(argv[1]); // 启动时传入客户端PID即可适配非父子进程场景 signal(SIGUSR1, my_handler); signal(SIGUSR2, my_handler); printf("服务端PID:%d\n", getpid()); // 打印PID供客户端传入 while (bit_cnt < 7) { pause(); if (bit_received) { res[bit_cnt] = current_bit ? '1' : '0'; bit_cnt++; bit_received = 0; kill(client_pid, SIGUSR1); // 发送确认信号给客户端 } } printf("收到二进制串:%s\n", res); return 0; }
客户端修改逻辑
新增等待确认逻辑,每发送一个信号后阻塞等待服务端的确认回执,收到回执后再发送下一个bit,避免连续发信号导致丢失。
客户端示例代码:
#include <signal.h> #include <unistd.h> #include <stdlib.h> #include <stdio.h> unsigned char target = 'g'; // 空确认信号处理函数,仅用来唤醒pause() void ack_handler(int signum) {} int main(int argc, char *argv[]) { pid_t server_pid = atoi(argv[1]); signal(SIGUSR1, ack_handler); printf("客户端PID:%d\n", getpid()); // 打印PID供服务端传入 for (int i = 6; i >= 0; i--) { int bit = (target >> i) & 1; if (bit) { kill(server_pid, SIGUSR1); } else { kill(server_pid, SIGUSR2); } pause(); // 等待服务端确认后再发下一个 } return 0; }
补充说明
如果需要传输完整字符串,可以约定传输结束标识(比如连续发送8个0作为结束位),服务端收到结束标识后再停止循环即可。
内容的提问来源于stack exchange,提问作者antiyro
相关产品推荐
相关产品推荐

