使用SIGUSR1、SIGUSR2信号传文本的C/S程序无响应信号问题排查
问题根因定位
1. 常规信号不排队导致丢包
SIGUSR1、SIGUSR2属于非实时标准信号,内核不会对这类信号排队:如果同一信号在进程未处理前被多次触发,仅会保留1次实例,其余直接丢弃。
- 你的交互逻辑是客户端每发1bit信号就阻塞等待服务端返回ACK,当单次发送长文本、或者短时间多次启动客户端时,信号碰撞概率陡增:要么客户端发的bit信号被服务端漏收,要么服务端返回的ACK被客户端漏收,双方都会卡在
pause()调用处永久等待,直接表现为程序卡住。
2. 全局状态无并发隔离
服务端用全局变量存储当前接收的bit计数、拼接中的字符,没有按发送方PID做状态隔离:
- 如果同时有多个客户端发信号,或者前一次客户端传输结束后状态没有正确重置,会直接打乱
counter和c的计数逻辑,导致服务端永远等不到counter归0,也就不会返回ACK信号。
3. 无异常兜底逻辑
- 客户端没有做入参合法性校验,若启动时参数数量不足,会读取非法内存得到错误的服务端PID或者传输内容,导致信号发送失败。
- 客户端和服务端都使用无超时的
pause()阻塞等待信号,只要出现一次丢包就会永久卡住,没有重试、超时退出的兜底机制。
修复方案
- 优先解决信号丢包问题:发送信号后增加微秒级的
usleep()延时降低碰撞概率,或者将异步信号处理逻辑改为用sigwaitinfo()同步等待信号,避免异步处理的竞态问题。 - 服务端按发送方PID维护独立的状态结构体,避免多客户端并发、多次传输的状态互相污染,每次识别到传输结束后主动清理对应PID的状态。
- 将
pause()替换为带超时的sigtimedwait(),增加丢包重试、超时退出的逻辑。 - 客户端传输完所有字符后,额外发送8个0bit作为传输结束标记,服务端识别到结束标记后主动重置状态,避免残留值影响下一次传输。
- 可优化点:将非标准的
act_one.__sigaction_u.__sa_sigaction写法替换为POSIX标准的act_one.sa_sigaction,提升代码可移植性。
内容的提问来源于stack exchange,提问作者Cleonia
相关产品推荐
相关产品推荐

