不能使用命名管道在C与shell脚本进行沟通 [英] Can't use named pipe from C to communicate with shell script
问题描述
我有一个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)
- 启动
omxplayer
实例:失败 - 启动
omxplayer
实例(更准确的时间WISE)在时间的未来,同时约定:失败 - 启动
omxplayer
实例:失败 - 启动,并立即暂停,然后取消暂停
omxplayer
实例(更准确的时间睿智): FAIL - 启动,并立即暂停,然后取消暂停(namedpipe 通过
呼应-np&GT)以同时在今后的时间后,商定方案(更准确的时间睿智):失败
- 启动,并立即暂停,然后取消暂停(通过
写(fd_of_named_pipe,'P',的sizeof('P'));
)omxplayer
以同时在今后的时间后,同意从C程序实例(更准确的时间睿智):待 - 重新实现
omxplayer
并调节播放速度赶上最快的球员:未来
以同时在今后的时间后,从约定壳
从Python脚本以
以同时在未来在约定时间从C程序(更准确的时间明智)
从Python脚本以同时在未来在约定时间
从C
omxplayer
实例; - Launch
omxplayer
instances from the shell at an agreed upon time in future at the same time: FAIL - Launch
omxplayer
instances from a Python script (more accurate time wise) at an agreed upon time in future at the same time: FAIL - Launch
omxplayer
instances from a C program (even more accurate time wise) at an agreed upon time in future at the same time: FAIL - 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 - 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 - 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 - 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屋!