无法使用 C 中的命名管道与 shell 脚本通信

标签 c shell named-pipes

我有一个这样的 C 程序(从 here 复制):

#include <fcntl.h>

#define PATH "testpipe"
#define MESSAGE "We are not alone"

int main()
{
   int fd;

   mkfifo ( PATH, 0666 );

   fd = open ( PATH, O_WRONLY );
   write ( fd, MESSAGE, sizeof ( MESSAGE ) );
   close ( fd );

   unlink ( PATH );
   return 0;
}

和一个像这样的shell脚本:
echo < testpipe

一旦我执行了 C 程序,echo 语句就会返回,但是 We are not alone不打印。我还尝试从命令行创建管道,并使用 mknod相反,它没有任何区别。为什么这不起作用?

编辑:

很多人指出问题出在echo。而不是 C ,问题是,我需要它来处理 echo 之类的东西(实际上是 omxplayer,因为我正在向它发出视频控制命令,即 p 用于暂停或 q 用于退出)。因此,我将不胜感激一些答案,说明如何更改 C 代码以使其与 echo 一起工作。声明,反之亦然

编辑:

我没有包含完整的代码,因为它使用 omxplayer并且相当大,但有些用户要求它,因此,这是我可以保留这个 MWE 的最小限度:
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define PIPEPATH "testpipe"
#define VIDEOPATH "Matrix.mkv"
#define MESSAGE "q"
#define VIDEOPLAYER "omxplayer"

int main()
{
   int fd;
   pid_t pid;
   pid_t wpid;
   int status;
   char shellCmd [ 1000 ];
   struct timespec time1, time2; //used for sleeping

   //Make pipe BEFORE forking
   mkfifo ( PIPEPATH, 0666 );

   if ( ( pid = fork () ) < 0 )
   {
      perror ( "Fork Failed\n" );
      return -1;
   }
   else if ( pid == 0 )
   { //first child keeps pipe open
      sprintf ( shellCmd, "tail -f /dev/null > %s", PIPEPATH );
      if ( system ( shellCmd ) == -1 )
      {
         printf ( "Error: %s\n", shellCmd );
         fflush(stdout);
      }
   }
   else{
      time1.tv_sec = 1L; //sleep for 1 second to let first child issue its command
      time1.tv_nsec = 0L; //Dont worry about milli seconds

      nanosleep ( &time1, &time2 );

      if ( ( pid = fork () ) < 0 )
      {
         perror ( "Fork Failed\n" );
         return -1;
      }
      else if ( pid == 0 )
      { //second child launches the movie
         sprintf ( shellCmd,  "cat %s | %s %s 2>&1 > /dev/null", PIPEPATH, VIDEOPLAYER,  VIDEOPATH );
         if ( system ( shellCmd ) == -1 )
         {
            printf ( "Error: %s\n", shellCmd );
            fflush(stdout);
         }
      }
      else
      {
         if ( ( pid = fork () ) < 0 )
         {
            perror ( "Fork Failed\n" );
            return -1;
         }
         else if ( pid == 0 )
         { //third child waits 5 seconds then quits movie
            time1.tv_sec = 5L; //sleep for 5 seconds
            time1.tv_nsec = 0L; //Dont worry about milli seconds

            nanosleep ( &time1, &time2 );

            printf ( "Sleep over, quiting movie\n");
            fflush(stdout);

            fd = open ( PIPEPATH, O_WRONLY );
            write ( fd, MESSAGE, sizeof ( MESSAGE ) );
            close ( fd );
         }
      }
   }

   //Note the first child will never exit as it is a blocking shell script
   while ( ( wpid = wait ( &status ) ) > 0 )
   {
      printf ( "Exit status of %d was %d (%s)\n", ( int ) wpid, status, ( status == 0 ) ? "accept" : "reject" );
      fflush(stdout);
   }

   unlink ( PIPEPATH );

   return 0;

正如我所指出的,程序永远不会退出,所以只需发出 Ctrl+C
}

编辑 3:

好的,我正在取得进展,看起来你给管道的东西和你得到的东西不是一回事,运行这个脚本并观察:
#include <stdio.h>
#include <fcntl.h>
#define PIPE_PATH "testpipe"

int main( int argc, char *argv[] ) {
   int fd;
   FILE *fp;
   char c;

   if ( atoi ( argv [ 1 ] ) == 1 )
   {
      printf ("Writer [%s]\n", argv[1]);

      mkfifo ( PIPE_PATH, 0666 );

      fd = open ( PIPE_PATH, O_WRONLY );
      c = getchar();
      write(fd, c, 1);

      close(fd);
   }
   else if ( atoi ( argv [ 1 ] ) == 2 )
   {
      printf ( "Reader [%s]\n", argv[1] );

      fp = fopen( PIPE_PATH, "r" );
      c = getc ( fp );
      putchar ( c );

      printf ( "\n" );
      fclose ( fp );

      unlink( PIPE_PATH );
   }

   return 0;
}

编辑 4:

J.F. Sebastian 提出了一些很好的问题,这是对这些问题的回应。我最终想要做的是同步 omxplayer 的 2 个或更多实例在 2 个或更多树莓派上播放同一部电影。 omxplayer-sync试图实现这一点,但它不准确,它是用 Python 编写的,不适合这个,而且它的方法是,IMO,不是一个好的方法。我正在沿着食物链往上走,尝试最简单的解决方案,看看它们是否可行。从最简单到最难,这是我迄今为止尝试过的(或计划尝试)
  • 发射omxplayer在 future 同一时间约定的时间从 shell 中的实例:失败
  • 发射omxplayer来自 Python 脚本的实例(更准确的时间)在 future 同一时间约定的时间:失败
  • 发射omxplayer来自 C 程序的实例(在时间上更准确)在 future 同一时间约定的时间:失败
  • 启动并立即暂停,然后取消暂停 omxplayer来自 Python 脚本的实例(更准确的时间)在 future 同一时间约定的时间:失败
  • 启动并立即暂停,然后取消暂停(通过 echo -n p > namedpipe )omxplayer来自 C 程序的实例(在时间上更准确)在 future 同一时间约定的时间:失败
  • 启动并立即暂停,然后取消暂停(通过 write ( fd_of_named_pipe, 'p', sizeof ( 'p') ); )omxplayer来自 C 程序的实例(在时间上更准确)在 future 同一时间约定的时间:待定
  • 重新实现 omxplayer并调节播放速度以 catch 最快的玩家: future

  • 基本上是在我投入大量时间来理解并修改 omxplayer 的源代码之前(7) 我想看看是否使用C的原生write ( fd_of_named_pipe, 'p', sizeof ( 'p') )操作比它的 system(echo -n p > namedpipe) 快call which forks a child 并调用 shell 写入命名管道(我的直觉告诉我它会更快,希望更准确)。如果这有效并且在 15 毫秒内取消暂停所有实例,太棒了,我不必查看 omxpleyer的源代码。如果没有,作为最后的手段,我将开始修改源代码。

    最佳答案

    使用为读取标准输入而设计的程序可能很有用。
    echo不这样做,但它会打印其命令行参数。那是一个区别。

    试试 cat .

    关于无法使用 C 中的命名管道与 shell 脚本通信,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20155872/

    相关文章:

    c - 基于 15 个种子的随机公式

    bash - shell脚本中的YYYY-MM-DD格式日期

    linux - 在 Linux 系统调用序列中区分 execve() 的解释器

    c - 命名管道有对应的设备驱动吗?

    c - 如何在 C 中的父进程和子进程之间共享结构数组?

    c - 如何获取 osx 子网中的事件 IP 和 MAC 地址列表

    c++ - size_t 的大小是否始终等于 void * 的大小

    c - IAR 链接器 CRC32 计算与 C(和其他网站)中计算的不匹配

    java - 从 Java 更改参数调用 Bash 脚本

    CallNamedPipe 和 TransactNamedPipe 不起作用