Я пытаюсь использовать сокет-пару, чтобы родительский процесс предоставлял входные данные дочернему процессу, который запускает другую программу (например, grep), а затем читал полученный результат. Программа зависает в цикле while, который читает выходные данные программы, которую исполняет дочерний элемент. Дочерний элемент дублирует stdin и stdout на свой конец пары сокетов, а родительский и дочерний элементы закрывают неиспользованный конец пары.
Интересно, что если ребенок исполняет программу, которую я написал (хорошо, я оторвал ее от Расширенного программирования Стивенса в среде Unix), все работает как положено. Однако, если дочерний файл исполняет grep (или какую-либо другую стандартную программу), родительский процесс неизменно зависает при попытке прочитать вывод. Я не могу сказать, не достигает ли вход grep или grep не может определить конец ввода, или выход как-то теряется.
Вот код:
#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);
}
}