studio programacion móviles desarrollo curso archivos aplicaciones c++ c

c++ - móviles - manual de programacion android pdf



popen simultanea leer y escribir (8)

Como ya se ha respondido, Popen trabaja en una dirección. Si necesita leer y escribir, puede crear una tubería con pipe (), abarcar un nuevo proceso con las funciones fork () y exec y luego redirigir sus entradas y salidas con dup2 (). De todos modos, prefiero exec sobre popen, ya que te da un mejor control sobre el proceso (por ejemplo, sabes su pid)

EDITADO:

Como se sugiere en los comentarios, una tubería puede usarse en una sola dirección. Por lo tanto tienes que crear tuberías separadas para leer y escribir. Como el ejemplo publicado anteriormente era incorrecto, lo eliminé y creé uno nuevo y correcto:

#include<unistd.h> #include<sys/wait.h> #include<sys/prctl.h> #include<signal.h> #include<stdlib.h> #include<string.h> #include<stdio.h> int main(int argc, char** argv) { pid_t pid = 0; int inpipefd[2]; int outpipefd[2]; char buf[256]; char msg[256]; int status; pipe(inpipefd); pipe(outpipefd); pid = fork(); if (pid == 0) { // Child dup2(outpipefd[0], STDIN_FILENO); dup2(inpipefd[1], STDOUT_FILENO); dup2(inpipefd[1], STDERR_FILENO); //ask kernel to deliver SIGTERM in case the parent dies prctl(PR_SET_PDEATHSIG, SIGTERM); //replace tee with your process execl("/usr/bin/tee", "tee", (char*) NULL); // Nothing below this line should be executed by child process. If so, // it means that the execl function wasn''t successfull, so lets exit: exit(1); } // The code below will be executed only by parent. You can write and read // from the child using pipefd descriptors, and you can send signals to // the process using its pid by kill() function. If the child process will // exit unexpectedly, the parent process will obtain SIGCHLD signal that // can be handled (e.g. you can respawn the child process). //close unused pipe ends close(outpipefd[0]); close(inpipefd[1]); // Now, you can write to outpipefd[1] and read from inpipefd[0] : while(1) { printf("Enter message to send/n"); scanf("%s", msg); if(strcmp(msg, "exit") == 0) break; write(outpipefd[1], msg, strlen(msg)); read(inpipefd[0], buf, 256); printf("Received answer: %s/n", buf); } kill(pid, SIGKILL); //send SIGKILL signal to the child process waitpid(pid, &status, 0); }

¿Es posible leer y escribir en un descriptor de archivos devuelto por popen? Tengo un proceso interactivo que me gustaría controlar a través de C. Si esto no es posible con popen, ¿hay alguna manera de evitarlo?


En uno de los backends de netresolve estoy hablando con un script y por lo tanto necesito escribir en su stdin y leer desde su stdout . La siguiente función ejecuta un comando con stdin y stdout redirigido a una tubería. Puedes usarlo y adaptarlo a tu gusto.

static bool start_subprocess(char *const command[], int *pid, int *infd, int *outfd) { int p1[2], p2[2]; if (!pid || !infd || !outfd) return false; if (pipe(p1) == -1) goto err_pipe1; if (pipe(p2) == -1) goto err_pipe2; if ((*pid = fork()) == -1) goto err_fork; if (*pid) { /* Parent process. */ *infd = p1[1]; *outfd = p2[0]; close(p1[0]); close(p2[1]); return true; } else { /* Child process. */ dup2(p1[0], 0); dup2(p2[1], 1); close(p1[0]); close(p1[1]); close(p2[0]); close(p2[1]); execvp(*command, command); /* Error occured. */ fprintf(stderr, "error running %s: %s", *command, strerror(errno)); abort(); } err_fork: close(p2[1]); close(p2[0]); err_pipe2: close(p1[1]); close(p1[0]); err_pipe1: return false; }

https://github.com/crossdistro/netresolve/blob/master/backends/exec.c#L46

(Utilicé el mismo código en Can popen () hacer tuberías bidireccionales como pipe () + fork ()? )


La razón por la que popen() y sus amigos no ofrecen comunicación bidireccional es que sería propensa a interbloqueos, debido al almacenamiento en búfer en el subproceso. Todas las soluciones improvisadas de tuberías y socketpair() discutidas en las respuestas sufren el mismo problema.

Bajo UNIX, no se puede confiar en que la mayoría de los comandos lean una línea e inmediatamente la procesen e impriman, excepto si su salida estándar es un tty. La razón es que stdio almacena de forma predeterminada la salida en el espacio de usuario, y difiere la llamada al sistema write() hasta que el búfer está lleno o la secuencia de stdio está cerrada (normalmente porque el programa o el script están a punto de salir después de haber visto EOF en la entrada) . Si escribe a la entrada estándar de dicho programa a través de una tubería, y ahora espera una respuesta de la salida estándar de ese programa (sin cerrar la tubería de entrada), la respuesta se atasca en los búferes de la estación y nunca saldrá . Esto es un punto muerto.

Puedes engañar a algunos programas orientados a líneas (p. Ej., grep ) para que no usen un búfer usando un pseudo-tty para hablar con ellos; libexpect(3) un vistazo a libexpect(3) . Pero en el caso general, tendría que volver a ejecutar un subproceso diferente para cada mensaje, permitiendo usar EOF para señalar el final de cada mensaje y hacer que se vacíen los búferes en el comando (o canalización de comandos). Obviamente no es algo bueno en cuanto al rendimiento.

Vea más información sobre este problema en la página del manual de perlipc (es para tuberías bidireccionales en Perl, pero las consideraciones de almacenamiento en búfer se aplican independientemente del idioma utilizado para el programa principal).


No puedes usar popen para usar tuberías de dos vías.

De hecho, algunos sistemas operativos no admiten canalizaciones de dos vías, en cuyo caso un par de socketpair ( socketpair ) es la única forma de hacerlo.


Popen funciona para mí en ambas direcciones (lectura y escritura). He estado utilizando una tubería popen() en ambas direcciones.

Leyendo y escribiendo un proceso hijo, stdin y stdout con el descriptor de archivo devuelto por popen (comando, "w")

Parece que funciona bien..

Asumí que funcionaría antes de saberlo mejor, y lo hace. Según las publicaciones anteriores, esto no debería funcionar ... lo que me preocupa un poco.

gcc en raspbian (raspbery pi debian)



Use forkpty (no es estándar, pero la API es muy buena y siempre puede dejar su propia implementación si no la tiene) y exec el programa con el que desea comunicarse en el proceso secundario.

Alternativamente, si la semántica tty no es de su agrado, puede escribir algo como forkpty pero utilizando dos conductos, uno para cada dirección de comunicación, o usando socketpair para comunicarse con el programa externo a través de un socket Unix.


popen() solo puede abrir el conducto en modo de lectura o escritura, no ambos. Echa un vistazo a this hilo para una solución.