Не могу использовать именованный канал из C для связи со сценарием оболочки
У меня есть программа на C, как это так (скопировано изВот):
#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;
}
и скрипт оболочки вот так:
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:
Я.Ф. Себастьян задал несколько хороших вопросов, это ответ на эти вопросы. В конечном итоге я пытаюсь синхронизировать 2 или более экземпляров omxplayer, воспроизводящих один и тот же фильм, на 2 или более малиновых писах.omxplayer-синхронизации пытается достичь этого, но это не точно, он написан на Python, который не подходит для этого, и его подход, IMO, не очень хороший. Я пробираюсь по пищевой цепи, пробуя самые простые решения, чтобы увидеть, являются ли они жизнеспособными. От самого простого к сложному, вот что я уже пробовал (или планирую попробовать)
запускomxplayer
экземпляры из оболочки в согласованное время в будущем одновременно:ПРОВАЛзапускomxplayer
экземпляры из скрипта Python (более точные по времени) в согласованное время в будущем одновременно:ПРОВАЛзапускomxplayer
экземпляры из программы на C (даже более точные по времени) в согласованное время в будущем одновременно:ПРОВАЛЗапустите и сразу приостановите, затем отпуститеomxplayer
экземпляры из скрипта Python (более точные по времени) в согласованное время в будущем одновременно:ПРОВАЛЗапустить и сразу же приостановить, а затем приостановить (черезecho -n p > namedpipe
) omxplayer
экземпляры из программы на С (более точные по времени) в согласованное время в будущем одновременно:ПРОВАЛЗапустить и сразу же приостановить, а затем приостановить (черезwrite ( fd_of_named_pipe, 'p', sizeof ( 'p') );
) omxplayer
экземпляры из программы на С (более точные по времени) в согласованное время в будущем одновременно:ОЖИДАНИЕПерепишитеomxplayer
и модулировать скорость игры, чтобы догнать самого быстрого игрока:БУДУЩЕЕВ основном, прежде чем вкладывать огромную часть своей жизни в понимание, а затем модифицировать исходный кодomxplayer
(7) я хочу посмотреть, если использовать родной язык Cwrite ( fd_of_named_pipe, 'p', sizeof ( 'p') )
операция быстрее, чем егоsystem(echo -n p > namedpipe)
вызов, который разветвляет дочерний элемент и вызывает оболочку для записи в именованный канал (моя догадка говорит мне, что это будет намного быстрее, и, надеюсь, более точным). Если это работает и останавливает все экземпляры с точностью до 15 мс, фантастика, мне не придется смотреть наomxpleyer
исходный код когда-либо. Если нет, то в крайнем случае я начну изменять исходный код.