J'essaie d'utiliser un socketpair pour qu'un processus parent fournisse une entrée à un processus enfant qui exécute un programme différent (par exemple, grep) et ensuite lire le résultat sortie. Le programme se bloque dans la boucle while qui lit la sortie du programme que l'enfant exécute. L'enfant dupe stdin et stdout à son extrémité de la socketpair et le parent et l'enfant ferment leur extrémité inutilisée de la paire. Il est intéressant de noter que si l'enfant exécute un programme que j'ai écrit (OK, je l'ai arraché à Stevens Advanced Programming dans l'environnement Unix), tout fonctionne comme prévu. Cependant, si l'exécutable exécute grep (ou un autre programme standard), le parent se bloque invariablement en essayant de lire la sortie. Je ne peux pas dire si l'entrée n'atteint pas grep ou si le grep ne peut pas déterminer la fin de l'entrée ou si la sortie est en quelque sorte perdue.communication bidirectionnelle using socketpair: bloque la sortie de lecture du processus enfant
Voici le code:
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <unistd.h>
#include <signal.h>
#include <cstdio>
#include <cerrno>
#include <iostream>
using namespace std;
void
sigpipe_handler(int sig, siginfo_t *siginfo, void * context) {
cout << "caught SIGPIPE\n";
pid_t pid;
if (errno == EPIPE) {
throw "SIGPIPE caught";
}
}
int main(int argc, char** argv) {
struct sigaction sa;
memset(&sa, '\0', sizeof(struct sigaction));
sa.sa_sigaction = sigpipe_handler;
sa.sa_flags = SA_SIGINFO | SA_RESTART;
sigaction(SIGPIPE, &sa, NULL);
int sp[2];
socketpair(PF_UNIX, SOCK_STREAM, AF_UNIX, sp);
pid_t childPid = fork();
if (childPid == 0) {
close(sp[0]);
if (dup2(sp[1], STDIN_FILENO) != STDIN_FILENO) throw "dup2 error to stdin";
if (dup2(sp[1], STDOUT_FILENO) != STDOUT_FILENO) throw "dup2 error to stdout";
execl("/bin/grep", "grep", "-n", "namespace", (char*)NULL);
} else {
close(sp[1]);
char line[80];
int n;
try {
while (fgets(line, 80, stdin) != NULL) {
n = strlen(line);
if (write(sp[0], line, n) != n) {
throw "write error to pipe";
}
if ((n=read(sp[0], line, 80)) < 0) { // hangs here
throw "read error from pipe";
}
if (n ==0) {
throw "child closed pipe";
break;
}
line[n] = 0;
if (fputs(line, stdout) == EOF) {
throw "puts error";
}
if (ferror(stdin)) {
throw "fgets error on stdin";
}
exit(0);
}
} catch (const char* e) {
cout << e << endl;
}
int status;
waitpid(childPid, &status, 0);
}
}
Intéressant. En utilisant strace, j'ai trouvé que grep attend une entrée après avoir reçu toutes les entrées que mon processus parent a dû donner (un processus fils qui a utilisé sscanf a bien fonctionné). J'ai essayé d'utiliser shutdown (pour lire) sur sp [0] mais ça n'a pas l'air de marcher. Je vais maintenant essayer d'utiliser close à la place. Je pense avoir supposé que les sockets n'étaient pas bloquants par défaut - j'essaierai certainement de paramétrer explicitement les sockets sur non-bloquants et en utilisant select. Merci! – roadrider