FIFO:从未从管道读取一个进程

问题描述 投票:0回答:1

我正在关注Linux管道的THIS TutorialsPoint指南,我特别需要使用FIFO。

但是,代码对于服务器端根本不起作用。

服务器文件无限期挂起或不读取任何内容,而客户端改为在FIFO上写入并立即读取它刚刚写入的内容。

如果您不想通过TutorialsPoint,这是这​​两个文件的完整代码:

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

#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;
}

当我运行两个进程时,这就是我得到的:

./ 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: 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

值得注意的是,在开始编写此问题之前,服务器的行为是完全不同的:与其一无所获并像您在此处看到的那样打印,它会在“读取”之后无限期挂起(而且我没有更改代码一位,但更改FIFO_FILE路径除外)

c++ c linux fifo mkfifo
1个回答
0
投票

您让服务器在写入后进入睡眠状态,但客户端没有。这样,客户端still可以在服务器可以获取其输出之前回读其自身的输出。因此,至少在两次写入之后您都应该添加一个睡眠,让服务器睡眠更长一点,以确保客户端首先唤醒以读取服务器输出。

同时访问未命名管道(通过pipe functions创建)的同一端是未定义的行为。尽管不确定命名管道,但我也假设那里几乎相同。通过简单的延迟(sleepusleep)同步并发访问此类终端也许可以解决问题,但这是一种非常不安全的方法。

我宁愿建议使用两个单独的管道,每个方向一个(根据需要打开相应的末​​端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, ...);
    
© www.soinside.com 2019 - 2024. All rights reserved.