现在,我尝试了解子进程的stdin/out/err的分叉/重新绑定,并在不泄漏任何资源的情况下正确管理资源(文件句柄、套接字)。
还有一些问题:在创建套接字对和分叉后,我在父 5 文件描述符和子文件中(stdin/out/err/socket1/socket2)。在子进程中,我需要关闭套接字对的“父”端。我在 fork 和dup()套接字的“客户端”之后close() stdin/out/err三次。在dup()之后,我是否需要关闭 dup 的“源”?我想是的......但我是对的吗?
当我以这种方式(见下文)创建第二个孩子时,资源处理是否正确?我试图严重依赖 RAII 来不泄漏任何 fds,但对吗?我错过了一件大事吗?
再见,提前感谢!
乔治
编辑:我修复了 rebind_and_exec_child 中的错误。
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <memory>
#include <cassert>
// this handle takes a fd, behaves like an int and makes sure the fd is closed again
class fdhandle {
public:
explicit fdhandle(int fd) {
mp_fd = std::shared_ptr<int>(new int, [=](int* pfd) {
close(*pfd);
delete pfd;
});
assert(mp_fd);
*mp_fd = fd;
}
operator int() {
assert(mp_fd);
return *mp_fd;
}
private:
std::shared_ptr<int> mp_fd;
};
void rebind_and_exec_child(fdhandle fd, std::string exe) {
// now close the std fds and connect them to the given fd
close(0); close(1); close(2);
// dup the fd three times and recreate stdin/stdout/stderr with fd as the target
if (dup(fd) != 0 || dup(fd) != 1 || dup(fd) != 2) {
perror("error duplicating socket for stdin/stdout/stderr");
exit(EXIT_FAILURE);
}
// now we can exec the new sub process and talk to it through
// stdin/stdout/stderr
char *arguments[4] = { exe.c_str(), exe.c_str(), "/usr/bin", NULL };
execv(exe.c_str(), arguments);
// this could should never be reached
perror("error: executing the binary");
exit(EXIT_FAILURE);
}
fdhandle fork_connected_child(std::string exe) {
// create the socketpair
int fd[2];
if (-1 == socketpair(PF_LOCAL, SOCK_STREAM, 0, fd)) {
perror("error, could not create socket pair");
exit(EXIT_FAILURE);
}
fdhandle fdparent(fd[0]); fdhandle fdchild(fd[1]);
// now create the child
pid_t pid = fork();
switch (pid) {
case -1: // could not fork
perror("error forking the child");
exit(EXIT_FAILURE);
break;
case 0: // child
rebind_and_exec_child(fdchild);
break;
default: // parent
return fdparent;
break;
}
}
int main(int argc, const char** argv) {
// create 2 childs
fdhandle fdparent1 = fork_connected_child("/bin/ls");
fdhandle fdparent2 = fork_connected_child("/bin/ls");
}