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

C语言FIFO传递结构体失败,求程序循环退出实现方案

问题描述

原始问题

尝试在C语言中通过FIFO传递结构体,但客户端无法接收并打印结构体数据。已定义结构体并写入管道,但不确定实现是否正确。

更新内容

已在辅助函数中添加switch语句,新增数字立方计算分支;目前需要实现程序循环运行直到主动退出的功能,询问可行实现方式:是否将if(mkfifo("ClientFifo", 0777) == -1)相关代码放入while循环,或在switch中新增退出分支?见过的其他服务器客户端示例多为持续循环,无退出机制。

附上更新后的代码:

Server.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
#include <fcntl.h>
#include <time.h>

struct Client {
    int clientNum;
    int systemCall;
    int num;
    int result;
}client;

struct Client get_student_data()
{
    struct Client s;
    s.clientNum = getpid();
    printf("Client Number:%d", s.clientNum);
    printf("\n");
    printf("Enter System Call number:");
    scanf("%d", &s.systemCall);
    printf("Enter Number:");
    scanf("%d", &s.num);
    printf("system call:%d\n", s.systemCall);

    switch (s.systemCall)
    {
    case 1:
        printf("Youre in case 1\n");
        s.result = s.num * s.num; 
        break;
    case 2:
        printf("Youre in case 2\n");
        s.result = s.num * s.num * s.num;
        break;
    default:
        printf("INVALID CHOICE\n");
        s.result = 0;
        break;
    }
    
    return s;
}

int main(int argc, char* argv[]) {//main
   
   //makes fifo  
   if(mkfifo("ClientFifo", 0777) == -1)
   {
        //error message in case fifo isnt created
        if(errno != EEXIST){
        printf("Could not create fifo file\n");
        return 1;
        }//end error checking
 
    //area to do work
    printf("\n");
    struct Client c1 = get_student_data();
    printf("\nClient number: %d\n",c1.clientNum);
    printf("System call number: %d\n",c1.systemCall);
    printf("Paramet number: %d\n",c1.num);
    printf("Result number: %d\n",c1.result);
    
    
    //opens and closes FIFO
    printf("Opening...\n");
    int fd = open("ClientFifo", O_WRONLY);
    printf("Opened\n");

    if(write(fd, &c1, sizeof(c1)) == -1){
    return 2;
    }
    //}//ends write
    //Closes fd
    printf("Written..\n");
    close(fd);
    
    return 0;
}//ends if fifo   
    
}//ends main

Client.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
#include <fcntl.h>
#include <time.h>

struct Client {
    int clientNum;
    int systemCall;
    int num;
    int result;
}client;

int main(int argc, char* argv[]) {

   if(mkfifo("ClientFifo", 0777)== -1)
   {
    if(errno != EEXIST){
    printf("Could not create fifo file\n");
    return 1;
    }
    printf("Opened\n");
    int fd = open("ClientFifo", O_RDONLY);
    if (fd == -1) {
        return 1;
    }
    
         printf("Reading\n");
          read(fd, &client, sizeof(client)); 
          printf("Client number:  %d\n", client.clientNum);
          printf("System call number:  %d\n", client.systemCall);
          printf("Parameter number %d\n", client.num);
          printf("Result %d\n", client.result);
      
    close(fd);
    
    return 0;

}//end if   
    
}//end main
问题分析与解决方案

一、结构体无法传递的核心问题

你的代码里mkfifo的逻辑完全写反了:

  • mkfifo成功时返回0,失败返回-1。当前代码仅在mkfifo失败(返回-1)时才执行后续的读写逻辑,这意味着如果FIFO创建成功,程序会直接跳过所有核心逻辑,直接return 0,根本没往管道里写数据!
  • Client端同样存在这个问题,只有mkfifo失败时才会尝试读取,逻辑完全错误。

修正后的Server主逻辑

int main(int argc, char* argv[]) {
    // 创建FIFO,成功或已存在都继续执行
    if(mkfifo("ClientFifo", 0777) == -1) {
        if(errno != EEXIST) {
            perror("Could not create fifo file");
            return 1;
        }
    }

    // 核心业务逻辑
    struct Client c1 = get_student_data();
    printf("\nClient number: %d\n",c1.clientNum);
    printf("System call number: %d\n",c1.systemCall);
    printf("Parameter number: %d\n",c1.num);
    printf("Result number: %d\n",c1.result);
    
    printf("Opening...\n");
    int fd = open("ClientFifo", O_WRONLY);
    if(fd == -1) {
        perror("Failed to open fifo");
        return 2;
    }
    printf("Opened\n");

    if(write(fd, &c1, sizeof(c1)) == -1) {
        perror("Failed to write to fifo");
        close(fd);
        return 3;
    }
    printf("Written..\n");
    close(fd);
    
    return 0;
}

修正后的Client主逻辑

int main(int argc, char* argv[]) {
    // 创建FIFO,成功或已存在都继续执行
    if(mkfifo("ClientFifo", 0777) == -1) {
        if(errno != EEXIST) {
            perror("Could not create fifo file");
            return 1;
        }
    }

    printf("Opening...\n");
    int fd = open("ClientFifo", O_RDONLY);
    if(fd == -1) {
        perror("Failed to open fifo");
        return 2;
    }
    printf("Opened\n");

    printf("Reading\n");
    if(read(fd, &client, sizeof(client)) == -1) {
        perror("Failed to read from fifo");
        close(fd);
        return 3;
    }
    printf("Client number:  %d\n", client.clientNum);
    printf("System call number:  %d\n", client.systemCall);
    printf("Parameter number: %d\n", client.num);
    printf("Result: %d\n", client.result);
      
    close(fd);
    return 0;
}

二、循环运行与主动退出的实现方案

推荐方案:在switch中新增退出分支,配合while循环

mkfifo只需要执行一次,不需要放入循环(FIFO创建后会一直存在,除非手动删除)。正确的做法是:

  1. 在switch中新增case 0作为退出分支,设置标志位终止循环。
  2. 将核心业务逻辑(获取输入、处理计算、写入FIFO)放入while循环中。

修正后的Server循环逻辑示例

struct Client get_student_data(int *should_exit)
{
    struct Client s;
    s.clientNum = getpid();
    printf("\nClient Number:%d\n", s.clientNum);
    printf("Enter System Call number (0 to exit):");
    scanf("%d", &s.systemCall);
    
    if(s.systemCall == 0) {
        *should_exit = 1;
        return s;
    }

    printf("Enter Number:");
    scanf("%d", &s.num);
    printf("System call:%d\n", s.systemCall);

    switch (s.systemCall)
    {
    case 1:
        printf("You're in case 1 (square)\n");
        s.result = s.num * s.num; 
        break;
    case 2:
        printf("You're in case 2 (cube)\n");
        s.result = s.num * s.num * s.num;
        break;
    default:
        printf("INVALID CHOICE\n");
        s.result = 0;
        break;
    }
    
    return s;
}

int main(int argc, char* argv[]) {
    // 创建FIFO,仅执行一次
    if(mkfifo("ClientFifo", 0777) == -1) {
        if(errno != EEXIST) {
            perror("Could not create fifo file");
            return 1;
        }
    }

    int should_exit = 0;
    while(!should_exit) {
        struct Client c1 = get_student_data(&should_exit);
        if(should_exit) {
            printf("Exiting...\n");
            break;
        }

        printf("\nClient number: %d\n",c1.clientNum);
        printf("System call number: %d\n",c1.systemCall);
        printf("Parameter number: %d\n",c1.num);
        printf("Result number: %d\n",c1.result);
        
        int fd = open("ClientFifo", O_WRONLY);
        if(fd == -1) {
            perror("Failed to open fifo");
            continue;
        }

        if(write(fd, &c1, sizeof(c1)) == -1) {
            perror("Failed to write to fifo");
            close(fd);
            continue;
        }
        printf("Written to fifo..\n");
        close(fd);
    }

    // 可选:退出时删除FIFO
    unlink("ClientFifo");
    return 0;
}

Client端循环接收的实现

如果需要Client持续接收直到主动退出,可以同样给Client加循环和退出逻辑:

int main(int argc, char* argv[]) {
    if(mkfifo("ClientFifo", 0777) == -1) {
        if(errno != EEXIST) {
            perror("Could not create fifo file");
            return 1;
        }
    }

    printf("Client running, press Ctrl+C to exit\n");
    while(1) {
        int fd = open("ClientFifo", O_RDONLY);
        if(fd == -1) {
            perror("Failed to open fifo");
            sleep(1);
            continue;
        }

        printf("\nReading from fifo...\n");
        ssize_t read_bytes = read(fd, &client, sizeof(client));
        if(read_bytes == -1) {
            perror("Failed to read from fifo");
            close(fd);
            continue;
        } else if(read_bytes == 0) {
            // 写端关闭,可能Server退出了
            printf("Server closed connection, exiting...\n");
            close(fd);
            break;
        }

        printf("Client number:  %d\n", client.clientNum);
        printf("System call number:  %d\n", client.systemCall);
        printf("Parameter number: %d\n", client.num);
        printf("Result: %d\n", client.result);
      
        close(fd);
    }

    unlink("ClientFifo");
    return 0;
}

额外注意事项

  1. 错误处理:添加perror打印具体错误信息,方便调试。
  2. FIFO特性:FIFO是半双工的,读写操作会阻塞直到对方打开对应的端。
  3. 权限问题:0777权限过于宽松,实际使用建议设置更严格的权限(比如0660)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 12:37:32