C语言客户端在scanf/fgets等待输入时无法响应SIGINT信号的解决求助
客户端SIGINT信号处理问题解决方案
问题描述
用C语言开发客户端-服务器程序,在Ubuntu终端运行时遇到以下问题:
- 客户端调用
fgets等待用户输入时,按下CTRL+C触发SIGINT信号 - 客户端未按预期终止(正常应向服务器发送终止信号并关闭连接)
- 终端显示
^C,后续输入仅在屏幕显示,按回车后无法发送给服务器,连接陷入阻塞
曾尝试用scanf配合EINTR_ABORT宏、带EINTR_ABORT的fgets,均未解决问题。相关代码如下:
scanf代码
while ((scanf("%s", buff)) == -1) EINTR_ABORT("Errore di scanf"); getchar();
fgets代码
if(fgets(buff_ID, sizeof(buff_ID), stdin)== NULL) EINTR_ABORT("Errore di fgets");
EINTR_ABORT宏定义
#define ISTANT_ABORT(warning) ({ fprintf(stderr, "%s: %s.\n", warning, strerror(errno)); exit(EXIT_FAILURE); }) #define EINTR_ABORT(warning) ({ if(errno != EINTR) ISTANT_ABORT(warning); })
解决方案
核心问题是默认SIGINT处理仅打断阻塞系统调用(如fgets/scanf),但你的EINTR_ABORT宏仅忽略EINTR错误,未执行终止清理逻辑。需自定义SIGINT信号处理函数,触发信号时完成资源清理与进程退出。
实现步骤
- 注册自定义SIGINT信号处理函数,替换默认行为
- 在信号处理函数中执行异步信号安全的操作:关闭客户端socket、向服务器发送终止标识、退出进程
- 调整输入循环逻辑,遇到EINTR错误时直接退出循环
完整代码示例
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <signal.h> #include <unistd.h> #include <sys/socket.h> #include <errno.h> int client_socket; // 全局socket,供信号处理函数访问 // SIGINT信号处理函数(仅调用异步信号安全的函数) void sigint_handler(int sig) { // 向服务器发送终止标识(按需定义格式) const char* terminate_msg = "CLIENT_EXIT"; write(client_socket, terminate_msg, strlen(terminate_msg)); // 关闭socket close(client_socket); // 用_exit直接退出,避免触发stdio缓冲区刷新(非信号安全) _exit(EXIT_FAILURE); } int main() { // 此处添加客户端socket初始化、连接服务器的代码... // 示例:client_socket = socket(...); connect(...); // 注册SIGINT信号处理 struct sigaction sa; memset(&sa, 0, sizeof(sa)); sa.sa_handler = sigint_handler; // 屏蔽其他信号,避免处理SIGINT时被打断 sigfillset(&sa.sa_mask); sigaction(SIGINT, &sa, NULL); char buff_ID[256]; while (1) { printf("请输入内容:"); fflush(stdout); // 强制刷新输出缓冲区,确保提示符及时显示 if (fgets(buff_ID, sizeof(buff_ID), stdin) == NULL) { // 若为EINTR,说明被SIGINT打断,退出循环 if (errno == EINTR) { break; } perror("fgets 读取失败"); close(client_socket); exit(EXIT_FAILURE); } // 去除换行符(可选) buff_ID[strcspn(buff_ID, "\n")] = '\0'; // 发送数据到服务器 if (write(client_socket, buff_ID, strlen(buff_ID)) == -1) { perror("发送数据失败"); close(client_socket); exit(EXIT_FAILURE); } } // 正常退出时清理资源 close(client_socket); return 0; }
关键说明
- 原宏失效原因:
EINTR_ABORT遇到EINTR错误时直接跳过,未触发终止逻辑,导致终端状态异常,后续输入失效。 - 使用
sigaction而非signal:signal函数行为在不同系统不一致,sigaction是POSIX标准,更可靠。 - 信号处理函数限制:仅调用异步信号安全函数(如
write、close、_exit),避免使用printf、fprintf等可能引发死锁的stdio函数。 - 刷新输出缓冲区:
fflush(stdout)确保输入提示符及时显示,避免行缓冲导致用户看不到输入提示。
内容的提问来源于stack exchange,提问作者ZODIACK
相关产品推荐
相关产品推荐

