键盘输入错误地重定向到命名管道读取

Posted

技术标签:

【中文标题】键盘输入错误地重定向到命名管道读取【英文标题】:Keyboard Input is wrongly redirected to Named Pipe read 【发布时间】:2018-06-21 17:52:50 【问题描述】:

我发布了一个earlier question,我还没有解决。我稍后会在那里尝试答案。但是,我目前面临一个奇怪的问题。

我在两个不同的ssh-ed 终端上运行我的readerwriter。 我在命名管道中的阅读器正在从键盘而不是命名管道读取输入。这是我的简单阅读器。

reader.c

#define PIPE_ID "aa"
int Pipe_FD = 0;

int main (int argc, char **argv)
    
  printf("Waiting on open\n");
  while(Pipe_FD = open(PIPE_ID, O_RDONLY) < 0) 
  

  printf("waiting on read\n");
  char ch;
  while(read(Pipe_FD, &ch, 1) > 0) 
    printf("Read: %c\t", ch);
    fflush(stdout);
  
  close(Pipe_FD);
  return 1;

我的编写器配置管道,向命名管道写入“Hi”,然后在退出前休眠 1 秒。

writer.c

#define PIPE_ID "aa"
int Pipe_FD = 0;

// This function configures named pipe
void configure_pipe() 
  if(mkfifo(PIPE_ID, 0666) != 0) 
    perror("mkfifo error\n");
  


void writeInPipe() 
  Pipe_FD = open(PIPE_ID, O_WRONLY);
  int num;
  if((num = write(Pipe_FD, "Hi", sizeof("Hi"))) < 0) 
    perror("Error in writing\t");
    exit(-1);
    else
    printf("Wrote bytes: %d\n", num);
  close(Pipe_FD);


int main() 
  configure_pipe();

  writeInPipe();
  sleep(1);
  unlink(PIPE_ID);

writer端正确输出:

Wrote bytes: 3

阅读器端的行为很奇怪。它正确地等待首先打开管道。然后,它不显示任何输出。如果我按“输入”,它只会显示为空白。如果按“ab”,则分别输出“a”和“b”。这是一个示例输出:

Waiting on open
waiting on read

Read:

        Read:

        Read:
a
        Read: a Read:
ab
        Read: a Read: b Read:

我首先运行阅读器,然后它等待open。当编写器启动时,它会等待read,但不显示任何输出。只有当我按下任何输入时,它才会显示一些东西。任何人都可以给出任何提示/想法到底发生了什么吗?

【问题讨论】:

不,它不会失败。我需要继续等待写作方面。这就是为什么它在while 不,@achal,while 似乎是故意的。读取器正在执行一个忙碌循环,等待写入器创建 fifo。这当然是有风险的,因为除了(尚未)存在的文件引起的错误之外,没有任何规定可以捕获错误。这里的busy-loop也有点浪费;如果在循环体中放置一个短暂的延迟,例如sleep(1),它将更好地利用系统资源并且更清晰。 【参考方案1】:

这里存在运算符优先级问题。赋值运算符 (=) 的优先级低于比较运算符,例如 &lt;。因此,这个while 循环...

while(Pipe_FD = open(PIPE_ID, O_RDONLY) < 0) 

被解释为

while (Pipe_FD = (open(PIPE_ID, O_RDONLY) < 0)) 

open() 返回小于 0 时,这具有您想要的语义,因为然后关系表达式的计算结果为 1,将 1 分配给Pipe_FD,整个表达式的值为 1,并且循环继续迭代。

open()成功,然而,实际的文件描述符仅用于与0的比较。当FD为非负时,比较结果为0,0赋值给Pipe_FD,整体表达式的值为0,循环终止。这样您就可以从文件描述符 0(标准输入)中读取,而不是从您打开的 FIFO 中读取。

通过适当使用括号来解决问题:

while ((Pipe_FD = open(PIPE_ID, O_RDONLY)) < 0) 

此外,在循环体中测试为什么打开失败会更加健壮和清晰。例如,

while ((Pipe_FD = open(PIPE_ID, O_RDONLY)) < 0) 
    if (errno != ENOENT) 
        perror("open");
        exit(1);
    

我建议还在那里放一个短暂的延迟,以减少对系统资源的要求。

【讨论】:

以上是关于键盘输入错误地重定向到命名管道读取的主要内容,如果未能解决你的问题,请参考以下文章

IO重定向及管道

重定向与管道

Linux重定向与管道

Linux管道符重定向与环境变量

Linux 重定向与管道符

Linux管道符和重定向与环境变量