Senden von Befehlen an einen untergeordneten Prozess über Pipe/Dup2 in C
Frage
Ich versuche, ein Fernsteuerungsprogramm für den Omxplayer auf meinem Raspberry Pi zu schreiben
Ich kann omxplayer dazu bringen, in einem untergeordneten Prozess einwandfrei zu laufen, aber es scheint mir nicht möglich zu sein, die Pipes richtig zum Laufen zu bringen, um tatsächlich Befehle an den untergeordneten Prozess zu senden.
int fd_pipe[2];
pipe (fd_pipe);
while(1) { // main accept() loop
printf("server: got connection from %s\n", s);
/* Attempt to fork and check for errors */
if( (pid=fork()) == -1){
fprintf(stderr,"Fork error. Exiting.\n"); /* something went wrong */
exit(1);
}
if (pid==0)
{ // this is the child process
dup2(0, fd_pipe[0]);
close(fd_pipe[1]);
if(execl("/usr/bin/top","top",NULL) == -1){
fprintf(stderr,"execl Error!");
exit(1);
}
//try and send command here
write(fd_pipe[0], "q", 1);
exit(0);
} else {
close(new_fd); // parent doesn't need this
dup2(1, fd_pipe[1]);
//try and send here too
write(fd_pipe[0], "q", 1);
}
}
Als ich mit top getestet und das Programm ausgeführt habe, kann ich die Top-Ausgabe im Terminalfenster sehen und den Befehl q im Fenster sehen, aber es sieht so aus, als ob er an den übergeordneten Prozess und nicht an den untergeordneten Prozess geht.Mache ich mit den Pipes etwas falsch oder ist es nicht möglich, Befehle an den erzeugten untergeordneten Prozess zu senden?
Ich habe versucht, die untergeordnete dup2-Anweisung so zu ändern, dass sie von der Pipe nach stdin kopiert wird
{ // this is the child process
dup2(fd_pipe[0], 0);
Aber dann startet top nicht mit einer fehlgeschlagenen TTY-Get-Nachricht
Lösung
Um mit einem Programm zu interagieren, das erwartet, ein Terminal manipulieren zu können, sollten Sie ein Pseudo-TTY verwenden.Dadurch wird das vermieden failed tty get
Fehler.
/*...*/
#include <pty.h>
void do_child () {
if (execlp("top", "top", (const char *)0) < 0) {
perror("exec top");
exit(EXIT_FAILURE);
}
/* NOTREACHED */
}
void do_parent (int fd, pid_t p) {
sleep(5);
char r;
write(fd, "q", 1);
while (read(fd, &r, 1) > 0) { write(1, &r, 1); }
waitpid(p, 0, 0);
close(fd);
}
int main () {
int fd;
pid_t p = forkpty(&fd, 0, 0, 0);
switch (p) {
case 0: do_child();
/* NOTREACHED */
case -1: perror("forkpty");
exit(EXIT_FAILURE);
default: break;
}
do_parent(fd, p);
return 0;
}
Beachten Sie, dass forkpty
ist kein POSIX, sondern eine Schnittstelle, die auf BSD- und Linux-Varianten von UNIX verfügbar ist.
Sie können ausführen top
im Batch-Modus, aber Sie können keinen Befehl zum Beenden verwenden.Du musst es töten.
void do_child () {
if (execlp("top", "top", "-b", (const char *)0) < 0) {
perror("exec top");
exit(EXIT_FAILURE);
}
/* NOT REACHED */
}
void do_parent (pid_t p) {
sleep(5);
if (kill(p, SIGINT) < 0) {
perror("kill");
exit(EXIT_FAILURE);
}
waitpid(p, 0, 0);
}
int main () {
pid_t p;
switch ((p = fork())) {
case 0: do_child();
case -1: perror("fork"); exit(EXIT_FAILURE);
default: break;
}
do_parent(p);
return 0;
}
Obwohl die Ausführung im Batch-Modus es Ihnen ermöglichen würde, den Prozess mit einem einfacheren Aufruf zu öffnen (z. B popen
wie mux vorschlägt), können Sie es nicht beenden, es sei denn, dieser Aufruf gibt die Prozess-ID des untergeordneten Elements zurück (ohne auszuführen). pkill
, oder durchsuchen Sie die Prozesstabelle, um den richtigen untergeordneten Prozess zum Beenden zu finden).
Ich glaube, Sie sind etwas verwirrt über die Verwendung dup2
.Die Handbuchseite verwendet die Begriffe oldfd
Und newfd
, und das bedeutet es oldfd
wird werden newfd
.Zur Veranschaulichung sehen Sie hier ein einfaches Programm, das stdout und stderr in eine Protokolldatei umleitet, eine Funktion aufruft und anschließend stdout und stderr wiederherstellt.
void do_something () {
fputs("Error message\n", stderr);
puts("This is regular output.");
fputs("Error message\n", stderr);
puts("This is regular output.");
}
int main () {
int fd = creat("/tmp/output.log", 0664);
int outfd = dup(fileno(stdout));
int errfd = dup(fileno(stderr));
fflush(stdout);
fflush(stderr);
dup2(fd, fileno(stdout));
dup2(fd, fileno(stderr));
setlinebuf(stdout);
do_something();
fflush(stdout);
fflush(stderr);
dup2(outfd, fileno(stdout));
dup2(errfd, fileno(stderr));
close(outfd);
close(errfd);
fputs("Error to the screen\n", stderr);
puts("Regular output to screen");
fputs("Error to the screen\n", stderr);
puts("Regular output to screen");
return 0;
}
Wie mux betonte, schreibt Ihr Programm an das falsche Ende der Pipe.Der pipe
Der Befehl gibt ein unidirektionales Paar von Dateideskriptoren zurück, wohin auch immer geschrieben wird fd_pipe[1]
kann daraus nachgelesen werden fd_pipe[0]
.