不能使用命名管道在C与shell脚本进行沟通 [英] Can't use named pipe from C to communicate with shell script

查看:373
本文介绍了不能使用命名管道在C与shell脚本进行沟通的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个C程序像这样(从复制这里):

I have a C program like so (copied from 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脚本,像这样:

and a shell script like so:

echo < testpipe

在我执行的C程序,回声语句返回,但我们并不孤单未打印。我也曾尝试创建管道在命令行,并用 mknod的相反,它使没有什么区别。这是为什么不工作?

Once I execute the C program, the echo statement returns, but We are not alone is not printed. I have also tried creating the pipe from the command line, and with mknod instead, and it makes no difference. Why is this not working?

编辑:

很多人都指出,这个问题是与回声而不是 C ,问题是,我需要它的东西,如回声 omxplayer 其实,我发出视频控制命令给它,即工作 p 为暂停或表示退出)。因此,我AP preciate一些答案指示如何改变C code,使其与回声语句的工作,而不是反之亦然

A lot of people have pointed out that the problem is with echo and not with C, problem is, I need it to work with something like echo (omxplayer actually, as I am issuing video control commands to it, ie. p for pause or q for quit). Therefore, I would appreciate some answers indicating how to change the C code to make it work with the echo statement, as opposed to vice versa

编辑:

我不包括完整的code,因为它使用 omxplayer ,是相当大的,但有些用户要求它,因此,这里是我的最低能保持这个MWE:

I didn't include the full code as it uses omxplayer and is rather large, but some users requested it, therefore, here is as minimal as I could keep this 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键
    }

As I pointed out, the program will never exit, so just issue a Ctrl+C }

修改3:

好吧,我不思进取,似乎有什么你给管你回来有什么不一样的东西,运行此脚本并观察:

Ok I am making progress, it seems that what you give to the pipe and what you get back are not the same thing, run this script and observe:

#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。塞巴斯蒂安问一些很好的问题,这是为了应对这些问题。我所最终试图做的是播放相同的电影上2个或更多树莓派同步omxplayer的2个或多个实例。 omxplayer同步的试图实现这一点,但它是不准确的,它是用Python编写的这是不适合这个,它的做法是,海事组织,没有一个好的。我的工作我的方式食物链尝试最简单的解决方案,看看他们是否可行。从简单到困难,这里是我迄今为止尝试过(或计划尝试)

J.F. Sebastian asked some good questions, this is in response to those questions. What I am ultimately trying to do is to synchronize 2 or more instances of omxplayer playing the same movie on 2 or more raspberry pis. omxplayer-sync tries to achieve this, but it is not accurate, it is written in Python which is not suitable for this, and its approach is, IMO, not a good one. I am working my way up the food chain trying out the easiest solutions to see if they are viable. From easiest to hardest, here is what I have tried so far (or plan on trying)


    以同时在今后的时间后,从约定壳
  1. 启动 omxplayer 实例:失败

  2. 从Python脚本以
  3. 启动 omxplayer 实例(更准确的时间WISE)在时间的未来,同时约定:失败

  4. 以同时在未来在约定时间从C程序(更准确的时间明智)
  5. 启动 omxplayer 实例:失败

  6. 从Python脚本以同时在未来在约定时间
  7. 启动,并立即暂停,然后取消暂停 omxplayer 实例(更准确的时间睿智): FAIL

  8. 从C omxplayer 实例;
  9. 启动,并立即暂停,然后取消暂停(namedpipe 通过呼应-np&GT)以同时在今后的时间后,商定方案(更准确的时间睿智):失败

  10. 启动,并立即暂停,然后取消暂停(通过写(fd_of_named_pipe,'P',的sizeof('P')); omxplayer 以同时在今后的时间后,同意从C程序实例(更准确的时间睿智):

  11. 重新实现 omxplayer 并调节播放速度赶上最快的球员:未来

  1. Launch omxplayer instances from the shell at an agreed upon time in future at the same time: FAIL
  2. Launch omxplayer instances from a Python script (more accurate time wise) at an agreed upon time in future at the same time: FAIL
  3. Launch omxplayer instances from a C program (even more accurate time wise) at an agreed upon time in future at the same time: FAIL
  4. Launch and immediately pause, then unpause omxplayer instances from a Python script (more accurate time wise) at an agreed upon time in future at the same time: FAIL
  5. Launch and immediately pause, then unpause (via echo -n p > namedpipe) omxplayer instances from a C program (more accurate time wise) at an agreed upon time in future at the same time: FAIL
  6. Launch and immediately pause, then unpause (via write ( fd_of_named_pipe, 'p', sizeof ( 'p') );) omxplayer instances from a C program (more accurate time wise) at an agreed upon time in future at the same time: PENDING
  7. Reimplement omxplayer and modulate play speeds to catch up with fastest player: FUTURE

基本上投入我生命中的一大部分转换为理解,然后修改 omxplayer 来源$ C ​​$ C(7)之前我想看看是否使用C的本地写(fd_of_named_pipe,'p',的sizeof('p'))操作比其系统快(回声-NP&GT; namedpipe)调用它叉一个孩子,调用外壳写入命名管道(我的直觉告诉我,它会快很多,希望更准确)。如果这个工程,并取消暂停到15毫秒内的所有情况下,太棒了,我也不会要看看 omxpleyer 的源$ C ​​$ C如初。如果不是这样,作为最后的手段,我将开始修改源$ C ​​$ C。

Basically before investing a huge chunk of my life into understanding and then modifying the source code of omxplayer (7) I want to see if using C's native write ( fd_of_named_pipe, 'p', sizeof ( 'p') ) operation is faster than its system(echo -n p > namedpipe) call which forks a child and calls the shell to write to the named pipe (my hunch tells me it will be much faster, and hopefully more accurate). If this works and unpauses all instances to within 15ms, fantastic, I won't have to look at omxpleyer's source code ever. If not, as a last resort I will start modifying the source code.

推荐答案

下面是你如何能模仿 {睡眠10;呼应-n磷; } | omxplayer 命令:

Here's how you could emulate { sleep 10; echo -n p ; } | omxplayer command:

/* for clock_nanosleep() */
#if ! defined(_POSIX_C_SOURCE)  || _POSIX_C_SOURCE < 200112L
#define _POSIX_C_SOURCE 200112L
#endif

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#include <unistd.h>

#define Close(FD) do {                                          \
    const int Close_fd = (FD);                                  \
    if (close(Close_fd) == -1)                                  \
      fprintf(stderr, "%s:%d: close(" #FD ") %d: %s\n",         \
              __FILE__, __LINE__, Close_fd, strerror(errno));   \
  }while(0)

static void _report_error_and_exit(const char* msg) {
  perror(msg);
  _exit(EXIT_FAILURE);
}

static void report_error_and_exit(const char* msg) {
  perror(msg);
  exit(EXIT_FAILURE);
}

int main(void) {
  int fd[2]; /* pipe */
  pid_t pid = -1;

  if (pipe(fd) == -1)
    report_error_and_exit("pipe");

  if ((pid = fork()) == -1)
    report_error_and_exit("fork");
  else if (pid == 0)  { /* child: sleep, write */
    Close(fd[0]); /* close unused read end of the pipe */

    { /* sleep until specified time */
      struct timespec endtime = {0};
      int r = -1;

      /* set some time into the future (just as an example) */
      if (clock_gettime(CLOCK_REALTIME, &endtime) < 0)
        _report_error_and_exit("clock_gettime");
      endtime.tv_sec += 10; /* seconds */

      /* NOTE: use settable system-wide real-time clock */
      while ((r = clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME,
                                  &endtime, NULL)) == EINTR)
        ; /* retry */

      if (r != 0)
        _report_error_and_exit("clock_nanosleep");
    }

    { /* write to the pipe */
      char c = 'p';
      ssize_t size = sizeof c, n = size, m = 0;
      while (n > 0) { /* until there is something to write */
        if ((m = write(fd[1], &c + (size - n), n)) > 0)
          n -= m;
        else if (errno != EINTR)
          _report_error_and_exit("write");
      }
    }
    _exit(EXIT_SUCCESS); /* child done */
  }

  /* parent: run `omxplayer < fd[0]` */
  Close(fd[1]); /* close unused write end of the pipe */

  /* redirect stdin */
  if (fd[0] != STDIN_FILENO) {
    if (dup2(fd[0], STDIN_FILENO) == -1)
      report_error_and_exit("dup2");
    else
      Close(fd[0]);
  }
  execlp("omxplayer", "omxplayer", NULL);
  _report_error_and_exit("execlp");
}

要试试吧,运行:

$ gcc *.c -lrt && ./a.out

应该启动 omxplayer 立即在当前时间加上10秒写它 P 。这是写使用绝对时间的睡眠。

It should start omxplayer immediately and write to it p at current time plus 10 seconds. It is written to use an absolute time for the sleep.

这应该帮助你打勾的 omxplayer同步列表中的下一个项目。但它不会解决在不同主机上的多个视频播放器播放同步的问题。

It should help you to tick the next item on your omxplayer-sync list. But it won't solve the issue of synchronizing playback on multiple video players on different hosts.

这篇关于不能使用命名管道在C与shell脚本进行沟通的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆