FIFO read() 函数卡在 c 中

FIFO read() function gets stuck in c

我正在尝试从一个进程中读取文本文件的字符串,然后通过 LINUX 上的命名管道将该字符串传送到另一个进程。问题是当我在控制台输入'./reader text.txt = receiver' 接收进程' read() 函数returns 错误如果我把行

fcntl(fd, F_SETFL, O_NONBLOCK);

或者如果我删除它就会卡在 read() 函数上。

这里是读取字符串的过程(reader)

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

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

 if(argc==4 && strcmp(argv1[2],"=") == 0){

 char mesaj[99999]; //message to be delivered

    char line[150];
    FILE *fp =fopen(argv1[1],"r");  //reading from a text file

    if(fp==NULL){

        printf("text file error!");
        exit(1);
    }


    while(fgets(line,sizeof(line),fp)){
        strcat(mesaj,line); //append every line to message

    }

    fclose(fp);

    mesaj[strlen(mesaj)-1]='[=11=]';

    int n =strlen(mesaj)+1;


   //printf("got the text  %s\n",mesaj);


    if(mkfifo("myFifo",0777)== -1 && errno!= EEXIST){ 
        printf("Pipe error");
        exit(1);
    }


    printf("opening\n");
    int fd= open("myFifo",O_RDWR);
    if(fd==-1){
        printf("open error");
        exit(1);
    }
    printf("opened");


    if( write(fd, mesaj,sizeof(char)*n)==-1){
        printf("write error");
        exit(1);
    }


    printf("written");

    close(fd);

    printf("closed");
    fflush(stdout);


   char mesajSizeChar[n];
   sprintf(mesajSizeChar, "%d", n);


    char *args[]={mesajSizeChar,NULL}; //send the message size as parameter for the other process
    char program[]="./";
    strcat(program,argv1[3]); // recieved process name as parameter
    execv(program,args); // call the other process
    perror("execv");


    return 0;
     }
 }

这是接收过程(接收者)

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

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

int mesajSize=atoi(argv1[0]); //convert message size to integer
char mesaj[99999];

printf("\ncame here\n");


int fd= open("myFifo",O_RDWR);
fcntl(fd, F_SETFL, O_NONBLOCK);
printf("\nopen \n");

if(fd==-1)
    printf("pipe error\n");


if(read(fd,mesaj,sizeof(char)*mesajSize)==-1)
printf("read error\n");


printf("read \n");
printf("\nworked: %s \n",mesaj);

close(fd);
return 0;

 }

问题是您在第一个进程中关闭了管道。管道没有任何永久存储,它只能在至少被一个进程打开时保存数据。当您关闭管道时,您写入的数据将被丢弃。

因此,当第二个进程尝试从管道读取时,没有可用的内容。

执行第二个进程时需要保持管道FD打开。删除 reader 程序中的 close(fd);

要使用 FIFO 或管道,发送方和接收方必须同时 运行,但您正试图按顺序 运行 它们。 FIFO 或管道没有持久存储,因此系统不允许您写入一个,除非至少有一个进程打开读取端,以便能够读取它。

通常,当没有 reader 时,尝试打开 FIFO 进行写入将被阻止,反之亦然。您的 reader 通过打开 FIFO 进行读取和写入来解决这个问题,即使它只打算写入。你会发现,如果它试图向 FIFO 发送太多数据,那么它就会阻塞,因为没有任何东西在读取数据,而且管道/FIFO 的缓冲容量有限。当它关闭 FIFO 的 fd 时,没有进程打开它,之前写入它的所有数据都将丢失。

您的接收器还错误地打开 FIFO 进行读取和写入,而它应该只打开它进行读取。没有数据可以从中读取,我希望从中读取的尝试会无限期地阻塞,除非您将其置于非阻塞模式。这似乎正是你所描述的。

要修复它,我会建议

  1. 从 reader 中取出启动接收器的代码。相反,单独启动 reader 和接收器。或者,reader 可以通过 fork()ing 开始 ,由此产生的子进程 execv()ing 接收器。

  2. reader 应该使用标志 O_WRONLY 打开 FIFO,接收方应该使用模式 O_RDONLY.

    [=50 打开它=]
  3. 你应该找到一种不同的方式来将消息长度从 reader 传递给接收者,或者更好的是,完全避免需要提前告诉它消息长度。例如,您可以发送一个初始固定长度的消息来传达主要消息数据的长度,但更典型的做法是让接收方继续读取数据,直到它看到 EOF。

  4. reader 将导致接收器通过显式或终止关闭它来查看 FIFO 上的 EOF。但是,这取决于接收器以只读模式打开它,并且没有其他写入器。

  5. reader 可能不应该尝试一次将整个消息缓冲到内存中。在任何情况下,都不应该假定 write() 调用将传输请求的全部字节数——return 值将告诉您实际传输了多少字节。您需要准备好在循环中使用多个 write() 调用来传输所有数据。

  6. 同样,接收方不能依赖单个 read() 调用来传输一次调用中请求的全部字节数,即使它有某种方式知道有多少字节即将到来。与write()一样,你需要准备使用多个read()来传输所有数据。