我想使用一個socketpair有一個父進程提供輸入到一個子進程,執行一個不同的程序(例如,grep),然後讀取結果輸出。該程序掛在while循環中,該循環從子程序讀取程序的輸出。小孩將stdin和stdout放在socketpair的末尾,父母和孩子都關閉了它們未使用的一端。有趣的是,如果孩子執行我編寫的程序(好吧,我把它從Unix環境中的Stevens Advanced Programming中剝離下來),一切都按預期工作。但是,如果孩子執行grep(或其他標準程序),則父母總會在嘗試讀取輸出時掛起。我無法判斷輸入是否達不到grep,或者如果grep無法確定輸入的結束或輸出是否以某種方式丟失。使用socketpair雙向通信:掛起從子進程讀取輸出
下面的代碼:
#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);
}
}
有趣。通過使用strace,我發現grep在接收到我父進程必須提供的所有輸入(使用sscanf工作正常的子進程)後正在等待輸入。我嘗試在sp [0]上使用shutdown(用於讀取),但它似乎不起作用。我現在將嘗試使用關閉。 我想我假設套接字默認是非阻塞的 - 我一定會嘗試明確地設置套接字爲非阻塞並使用select。 謝謝! – roadrider 2010-08-31 21:44:42