简体   繁体   English

FIFO:一个进程从不从 pipe 读取

[英]FIFO: One process never reads from pipe

I'm following THIS TutorialsPoint guide to Linux Piping, and I specifically need to use FIFOs.我正在关注 Linux 管道的这个TutorialsPoint 指南,我特别需要使用 FIFO。

However, the code doesn't work at all for the server side.但是,该代码根本不适用于服务器端。

The server file either hangs indefinitely or it reads nothing, while the client instead writes on the FIFO and immediately reads it has just written.服务器文件要么无限期挂起,要么什么也不读取,而客户端则写入 FIFO 并立即读取它刚刚写入的内容。

Here's the full code for both files in case you don't want to go through TutorialsPoint:这是两个文件的完整代码,以防您不想通过 TutorialsPoint go:

fifoserver_twoway.cpp fifoserver_twoway.cpp

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

#define FIFO_FILE "/tmp/fifo_twoway"

void reverse_string(char *);
int main() {
   int fd;
   char readbuf[80];
   char end[10];
   int to_end;
   int read_bytes;

   /* Create the FIFO if it does not exist */
   mkfifo(FIFO_FILE, S_IFIFO|0640);
   strcpy(end, "end");
   fd = open(FIFO_FILE, O_RDWR);
   while(1) {
      read_bytes = read(fd, readbuf, sizeof(readbuf));
      readbuf[read_bytes] = '\0';
      printf("FIFOSERVER: Received string: \"%s\" and length is %d\n", readbuf, (int)strlen(readbuf));
      to_end = strcmp(readbuf, end);

      if (to_end == 0) {
         close(fd);
         break;
      }
      reverse_string(readbuf);
      printf("FIFOSERVER: Sending Reversed String: \"%s\" and length is %d\n", readbuf, (int) strlen(readbuf));
      write(fd, readbuf, strlen(readbuf));
      /*
      sleep - This is to make sure other process reads this, otherwise this
      process would retrieve the message
      */
      sleep(2);
   }
   return 0;
}

void reverse_string(char *str) {
   int last, limit, first;
   char temp;
   last = strlen(str) - 1;
   limit = last/2;
   first = 0;

   while (first < last) {
      temp = str[first];
      str[first] = str[last];
      str[last] = temp;
      first++;
      last--;
   }
   return;
}

fifoclient_twoway.cpp fifoclient_twoway.cpp

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

#define FIFO_FILE "/tmp/fifo_twoway"
int main() {
   int fd;
   int end_process;
   int stringlen;
   int read_bytes;
   char readbuf[80];
   char end_str[5];
   printf("FIFO_CLIENT: Send messages, infinitely, to end enter \"end\"\n");
   fd = open(FIFO_FILE, O_CREAT|O_RDWR);
   strcpy(end_str, "end");

   while (1) {
      printf("Enter string: ");
      fgets(readbuf, sizeof(readbuf), stdin);
      stringlen = strlen(readbuf);
      readbuf[stringlen - 1] = '\0';
      end_process = strcmp(readbuf, end_str);

      //printf("end_process is %d\n", end_process);
      if (end_process != 0) {
         write(fd, readbuf, strlen(readbuf));
         printf("FIFOCLIENT: Sent string: \"%s\" and string length is %d\n", readbuf, (int)strlen(readbuf));
         read_bytes = read(fd, readbuf, sizeof(readbuf));
         readbuf[read_bytes] = '\0';
         printf("FIFOCLIENT: Received string: \"%s\" and length is %d\n", readbuf, (int)strlen(readbuf));
      } else {
         write(fd, readbuf, strlen(readbuf));
         printf("FIFOCLIENT: Sent string: \"%s\" and string length is %d\n", readbuf, (int)strlen(readbuf));
         close(fd);
         break;
      }
   }
   return 0;
}

When I run both processes, this is what I get:当我运行这两个进程时,这就是我得到的:

./fifoserver_twoway ./fifoserver_twoway

FIFOSERVER: Received string: "" and length is 0
FIFOSERVER: Sending Reversed String: "" and length is 0
FIFOSERVER: Received string: "" and length is 0
FIFOSERVER: Sending Reversed String: "" and length is 0

./fifoclient_twoway ./fifoclient_twoway

FIFOCLIENT: Sent string: "ciao" and string length is 4
FIFOCLIENT: Received string: "ciao" and length is 4
Enter string: why won't you reverse?
FIFOCLIENT: Sent string: "why won't you reverse?" and string length is 29
FIFOCLIENT: Received string: "why won't you reverse?" and length is 29

It's also worth noting that before starting to write this question, the server behaviour was completely different: instead of receiving nothing and printing like you see here, it would hang indefinitely after the "read" (and I haven't changed the code one bit, except for changing the FIFO_FILE path)还值得注意的是,在开始写这个问题之前,服务器的行为是完全不同的:不像你在这里看到的那样接收和打印,它会在“读取”之后无限期挂起(而且我没有改变一点代码, 除了改变 FIFO_FILE 路径)

You let the server sleep after writing – but not the client.你让服务器在写完之后休眠——而不是客户端。 That way, the client still might read its own output back before the server can fetch it.这样,客户端仍然可以在服务器获取之前读取它自己的 output。 So at very least you should add a sleep after both writes, letting the server sleep a bit longer to make sure the client wakes up first to read the servers output.所以至少你应该在两次写入之后添加一个睡眠,让服务器睡眠更长一点,以确保客户端首先醒来以读取服务器 output。

Accessing the same end of unnamed pipes (created via pipe functions ) concurrently is undefined behaviour.同时访问未命名管道的同一端(通过pipe 函数创建)是未定义的行为。 While not sure for named pipes, I'd assume pretty much the same there as well.虽然不确定命名管道,但我认为那里也几乎相同。 Synchronising concurrent access to such ends via simple delays ( sleep , usleep ) might perhaps do the trick, but it is a pretty unsafe method.通过简单的延迟( sleepusleep )同步对这些目的的并发访问可能会奏效,但这是一种非常不安全的方法。

I'd rather recommend two separate pipes instead (as Tony Tannous proposed already), one for each direction (open the respective ends RDONLY or WRONLY as needed), then you get full duplex communication instead of half duplex and you don't need further synchronisation either (delays in most simple variant):我宁愿推荐两个单独的管道(正如Tony Tannous已经建议的那样),每个方向一个(根据需要打开各自的末端RDONLYWRONLY ),然后您将获得全双工通信而不是半双工,并且您不需要进一步同步(在最简单的变体中延迟):

// server
int fd_cs = open(FIFO_FILE_CS, O_RDONLY);
int fd_sc = open(FIFO_FILE_SC, O_WRONLY);
    read(fd_cs, ...);
    write(fd_sc, ...);

// client
int fd_cs = open(FIFO_FILE_CS, O_WRONLY);
int fd_sc = open(FIFO_FILE_SC, O_RDONLY);
    write(fd_cs, ...);
    read(fd_sc, ...);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM