You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Linux终端通信程序FIFO写入无响应问题排查求助

问题排查与修复建议

你的程序无响应且功能失效,核心是架构设计缺陷+多处逻辑错误,下面逐一拆解问题:

1. 进程间全局变量完全不共享(致命问题)

server和client是独立的Linux进程,你定义的全局users数组在两个进程中是完全分开的内存空间——客户端往数组里加用户,服务器根本看不到;服务器的用户列表永远是空的,自然无法转发消息。

修复:必须让服务器统一管理用户列表,所有客户端的注册、消息请求都通过server_fifo发送给服务器处理,服务器再负责将消息转发到目标客户端的FIFO。

2. 客户端完全没处理终端输入(直接导致无响应)

client函数启动后,死循环读取自己的FIFO,但用户在终端输入的内容(比如TO alice hello)根本没被程序读取——程序没监听标准输入(stdin),所以你输入任何内容,程序都不会有反应。

修复:用select()或poll()同时监听stdin和用户FIFO,当stdin有输入时读取并解析命令:

// 客户端新增监听逻辑
fd_set read_fds;
FD_ZERO(&read_fds);
FD_SET(STDIN_FILENO, &read_fds);
FD_SET(user_fifo, &read_fds);
int max_fd = user_fifo > STDIN_FILENO ? user_fifo : STDIN_FILENO;

while(1) {
    fd_set tmp_fds = read_fds;
    int ret = select(max_fd + 1, &tmp_fds, NULL, NULL, NULL);
    if(ret == -1) {
        perror("select");
        exit(1);
    }
    // 处理终端输入
    if(FD_ISSET(STDIN_FILENO, &tmp_fds)) {
        char input[MSG_SIZE];
        fgets(input, sizeof(input), stdin);
        // 解析TO命令,发送给服务器
        if(strstr(input, "TO ") == input) {
            char server_msg[MSG_SIZE + 64];
            snprintf(server_msg, sizeof(server_msg), "MSG %s %s", name, input+3);
            int server_fd = open("server_fifo", O_WRONLY);
            if(server_fd != -1) {
                write(server_fd, server_msg, strlen(server_msg));
                close(server_fd);
            }
        }
    }
    // 处理FIFO消息(接收服务器转发的消息)
    if(FD_ISSET(user_fifo, &tmp_fds)) {
        // 原有的读取FIFO逻辑
        ...
    }
}

3. 参数传递完全错误

main函数调用client(fd, sender_pid, name)时:

  • fd是未初始化的垃圾值,后续如果用这个fd写数据直接会出错
  • sender_pid硬编码为-1,毫无意义

修复:client函数不需要这两个参数,直接在函数内部用getpid()获取自身PID,用STDIN_FILENO处理终端输入,修改函数定义为void client(char *name)。

4. FIFO逻辑混乱,通信链路断裂

  • 客户端注册流程缺失:用户登录后,没有向server_fifo发送注册请求,服务器永远不知道有新用户加入
  • FIFO路径错误:客户端发送消息时,用users[to_user].name作为FIFO路径打开,但服务器根本没保存用户的FIFO路径;而且客户端和服务器的users数组不共享,客户端根本拿不到目标用户的信息
  • 未处理FIFO打开失败:服务器和客户端打开FIFO后,都没检查返回值是否为-1,比如服务器启动时如果mkfifo失败(比如已存在),后续open会出错,但程序没处理

修复:

  1. 客户端登录时,立即向server_fifo发送注册消息:
// client函数开头
int server_fd = open("server_fifo", O_WRONLY);
if(server_fd == -1) {
    perror("connect to server");
    exit(1);
}
char reg_msg[64];
snprintf(reg_msg, sizeof(reg_msg), "REGISTER %s %s", name, fifo_name);
write(server_fd, reg_msg, strlen(reg_msg));
close(server_fd);
  1. 服务器接收注册消息后,将用户信息(name、fifo路径、fd)保存到自己的users数组:
// server函数中解析消息
if(strstr(buffer, "REGISTER ") == buffer) {
    char *name = strtok(buffer+9, " ");
    char *fifo = strtok(NULL, " ");
    if(name && fifo) {
        int fifo_fd = open(fifo, O_WRONLY | O_NONBLOCK);
        if(fifo_fd != -1) {
            strncpy(users[num_users].name, name, sizeof(users[num_users].name)-1);
            users[num_users].name[sizeof(users[num_users].name)-1] = '\0';
            strncpy(users[num_users].fifo, fifo, sizeof(users[num_users].fifo)-1);
            users[num_users].fifo[sizeof(users[num_users].fifo)-1] = '\0';
            users[num_users].fd = fifo_fd;
            num_users++;
        }
    }
}
  1. 客户端发送消息时,统一发送给服务器,由服务器转发到目标用户的FIFO,而不是客户端直接操作目标FIFO。

5. 字符串缓冲区溢出

struct user的name字段是20字节,但客户端注册时用strncpy(u.name, tok, 31),超过了字段长度,会导致缓冲区溢出,破坏进程内存,引发未知错误。

修复:

strncpy(u.name, tok, sizeof(u.name)-1);
u.name[sizeof(u.name)-1] = '\0';

6. 其他细节问题

  • 服务器启动时,mkfifo如果遇到已存在的FIFO会报错,应该先检查是否存在,或者用mkfifo(..., 0666) || errno != EEXIST忽略已存在的情况
  • 客户端的UNREGISTER逻辑完全错误,sender_pid是-1,根本找不到用户,而且消息拼接用了未处理的msg变量,逻辑混乱
  • 所有read/write操作都应该检查返回值,处理错误情况

内容的提问来源于stack exchange,提问作者Matthew

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 06:12:07