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创建后会一直存在,除非手动删除)。正确的做法是:
- 在switch中新增
case 0作为退出分支,设置标志位终止循环。 - 将核心业务逻辑(获取输入、处理计算、写入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; }
额外注意事项
- 错误处理:添加
perror打印具体错误信息,方便调试。 - FIFO特性:FIFO是半双工的,读写操作会阻塞直到对方打开对应的端。
- 权限问题:0777权限过于宽松,实际使用建议设置更严格的权限(比如0660)。
内容的提问来源于stack exchange,提问作者jjmoe43
相关产品推荐
相关产品推荐

