C语言管道信号处理实现的正确性验证问询
信号处理与命名管道实现问题排查
问题背景
外部应用Exchange会创建两个命名管道pe_exchange_<N>和pe_trader_<N>(<N>由命令行参数传入),我的程序Trader需要完成以下操作:
- 从
pe_exchange_<N>管道读取Exchange发送的内容(最大50字节) - 读取完成后,向作为父进程的Exchange发送
SIGUSR1信号 - 向
pe_trader_<N>管道写入消息"Hello"
预期流程:
Exchange → Trader:Hi There!
Trader → Exchange:Hello
但当前代码既无法检测到SIGUSR1信号,也无法打印Exchange发送的消息,以下是我的实现代码:
void signal_handler(int SIG); volatile sig_atomic_t g_sigint_flag = 0; volatile sig_atomic_t g_sigusr1_flag = 0; int fd1; int fd2; void exchange_signal_handler(int signo); int main(int argc, char ** argv) { char exchange[100]; char trader[100]; sprintf(exchange, "/tmp/pe_exchange_%s", argv[1]); sprintf(trader, "/tmp/pe_trader_%s", argv[1]); fd1 = open(exchange,O_RDONLY); fd2 = open(trader,O_WRONLY); if (fd1== -1) { perror("open pipe failed"); return 1; } if (fd2== -1) { perror("open pipe failed"); return 1; } if (signal(SIGINT, signal_handler) == SIG_ERR) { printf("Unable to register signal handler for SIGINT\n"); return 1; } if (signal(SIGUSR1, exchange_signal_handler) == SIG_ERR) { printf("Unable to register exchange signal handler for SIGUSR1\n"); return 1; } pid_t exchange_pid = getppid(); while (1) { if (g_sigusr1_flag) { g_sigusr1_flag = 0; printf("This is working partially");// Reset the flag } sleep(1); } close(fd2); close(fd1); return 0; } void signal_handler(int SIG) { if (SIG == SIGINT) { printf("Terminated\n"); g_sigint_flag = 1; } } void exchange_signal_handler(int signo) { if (signo == SIGUSR1) { printf("Received SIGUSR1 signal from exchange\n"); g_sigusr1_flag = 1; } }
问题分析与修正
你的代码存在几个核心问题:
1. 完全缺失管道读取逻辑
代码里没有任何从pe_exchange_<N>管道读取数据的代码,根本不会处理Exchange发送的消息,自然也无法触发后续的信号发送和回复操作。
2. 信号逻辑完全搞反
根据需求,应该是Trader读取到管道数据后,主动向Exchange发送SIGUSR1,但你当前的代码是在等待Exchange向Trader发SIGUSR1,完全和需求相悖。
3. PID获取的潜在问题
如果Exchange不是Trader的直接父进程,getppid()会拿到错误的PID,导致信号发送失败。如果Exchange会通过管道传递自身PID,或者需要其他方式获取正确PID,需调整这部分逻辑。
修正后的代码示例
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <signal.h> #include <fcntl.h> #include <string.h> #include <errno.h> volatile sig_atomic_t g_sigint_flag = 0; int fd_exchange; // 读取Exchange消息的管道 int fd_trader; // 向Exchange发送消息的管道 pid_t exchange_pid; void signal_handler(int signo) { if (signo == SIGINT) { printf("Terminated\n"); g_sigint_flag = 1; } } int main(int argc, char **argv) { if (argc != 2) { fprintf(stderr, "Usage: %s <pipe_suffix>\n", argv[0]); return 1; } char exchange_pipe[100]; char trader_pipe[100]; snprintf(exchange_pipe, sizeof(exchange_pipe), "/tmp/pe_exchange_%s", argv[1]); snprintf(trader_pipe, sizeof(trader_pipe), "/tmp/pe_trader_%s", argv[1]); // 打开管道:命名管道需两端都打开才会成功,这里会阻塞等待Exchange创建并打开管道 fd_exchange = open(exchange_pipe, O_RDONLY); if (fd_exchange == -1) { perror("Failed to open exchange pipe"); return 1; } fd_trader = open(trader_pipe, O_WRONLY); if (fd_trader == -1) { perror("Failed to open trader pipe"); close(fd_exchange); return 1; } // 注册SIGINT信号处理(用于退出程序) if (signal(SIGINT, signal_handler) == SIG_ERR) { perror("Failed to register SIGINT handler"); close(fd_trader); close(fd_exchange); return 1; } // 获取Exchange的PID:假设Exchange是当前进程的父进程,否则需调整获取方式 exchange_pid = getppid(); char buffer[51]; // 50字节内容+1字节终止符 ssize_t read_len; while (!g_sigint_flag) { // 从Exchange管道读取数据 read_len = read(fd_exchange, buffer, sizeof(buffer)-1); if (read_len == -1) { if (errno == EINTR) continue; // 被信号中断,重试读取 perror("Failed to read from exchange pipe"); break; } else if (read_len == 0) { printf("Exchange closed the pipe\n"); break; } // 确保字符串终止 buffer[read_len] = '\0'; printf("Received from Exchange: %s\n", buffer); // 向Exchange发送SIGUSR1信号 if (kill(exchange_pid, SIGUSR1) == -1) { perror("Failed to send SIGUSR1 to Exchange"); } // 向Trader管道写入回复消息 const char *reply = "Hello"; if (write(fd_trader, reply, strlen(reply)) == -1) { perror("Failed to write to trader pipe"); } } // 清理资源 close(fd_trader); close(fd_exchange); return 0; }
关键修正点说明
- 添加了管道读取逻辑,使用
read()获取数据,处理信号中断的情况(EINTR) - 调整信号逻辑:读取数据后主动向Exchange发送
SIGUSR1,而非等待信号 - 增加参数检查,确保命令行参数正确传入
- 使用
snprintf替代sprintf,避免缓冲区溢出 - 完善资源清理,确保管道描述符被正确关闭
- 处理管道关闭的情况(
read()返回0)
内容的提问来源于stack exchange,提问作者HyperCoderSuperion
相关产品推荐
相关产品推荐

