C++ c++;ServerSocket()、FD_CLOEXEC、fork();execl()
我在尝试在我的应用程序中设置命令的背景时遇到问题,因此我需要使用双叉并清除一些设置,因此这是我的结果:C++ c++;ServerSocket()、FD_CLOEXEC、fork();execl(),c++,C++,我在尝试在我的应用程序中设置命令的背景时遇到问题,因此我需要使用双叉并清除一些设置,因此这是我的结果: if((pid = fork()) < 0) perror("Error with Fork()"); else if(pid > 0) { return ""; } if (setsid()==-1) { Log("failed to become a session leader"); } if (chdir("/") == -1) { Log
if((pid = fork()) < 0)
perror("Error with Fork()");
else if(pid > 0) {
return "";
}
if (setsid()==-1) {
Log("failed to become a session leader");
}
if (chdir("/") == -1) {
Log("failed to change working directory");
}
umask(0);
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
if (open("/dev/null",O_RDONLY) == -1) {
Log("failed to reopen stdin");
}
if (open("/dev/null",O_WRONLY) == -1) {
Log("failed to reopen stdout");
}
if (open("/dev/null",O_RDWR) == -1) {
Log("failed to reopen stderr");
}
signal(SIGHUP, SIG_IGN);
Log("No return, forking..");
if((pid = fork()) < 0)
perror("Error with Fork()");
else if(pid > 0) {
return "";
} else {
if(execl("/bin/bash", "/bin/bash", "-c", cmddo, (char*) 0) < 0) perror("execl()");
exit(0);
}
在我的最后一个问题中,我被告知要在套接字上使用FD_CLOEXEC,但我不知道如何做到这一点——而谷歌(加上堆栈)在这方面并没有给我多少帮助
如何在我的ServerSocket()上FD_CLOEXEC,以便在我fork/excl子进程时它不会挂起我的套接字
谢谢:D
回答:
如下所述,为了清除fd,我的代码实际上有这样一个功能,它对我很有用:
struct rlimit rl;
int i;
if (rl.rlim_max == RLIM_INFINITY)
rl.rlim_max = 1024;
for (i = 0; (unsigned) i < rl.rlim_max; i++)
close(i);
struct rlimit rl;
int i;
if(rl.rlim_max==rlim_无穷大)
rl.rlim_max=1024;
对于(i=0;(无符号)i
FD\u CLOEXEC
是一个可以在文件描述符上设置的标志——其作用是当持有句柄的进程调用exec()
时,描述符关闭
使用
设置旗帜;要使其工作,您需要访问实际的文件描述符
另外,setsid()
足以使您与父进程组解除关联,虽然doublefork()
也可以工作,但它不会为您赢得嵌入式进程组的布朗尼点数
最后,无法保证在关闭前三个文件描述符后,下一个打开的FD将是这三个文件描述符;最好使用
fd newstdin = open(...);
if(dup2(newstdin, STDIN_FILENO) != 0) { /* handle error */ }
close(newstdin);
我想我确实理解了第二点和第三点,但是我的第一点,也是主要的一点,我仍然很困惑——ServerSocket()是否构成fd?我的应用程序中唯一的fd是当它被设置为守护程序时,我已经fd_CLOEXEC了。fd0=打开(“/dev/null”,O_RDWR);fcntl(fd0、F_SETFD、FD_CLOEXEC);谢谢ServerSocket内部有一个fd,是的。这是一个实现细节,原则上不应涉及您的应用程序,但通常有一种方法可以打破抽象(或者,尝试了解是否可以教ServerSocket设置close on exec标志,这是正确的做法)。请注意,您不应该关闭
exec()
上的标准文件描述符--这些文件描述符将由子级继承,否则首先设置它们是没有意义的。原则相当简单:当这三个文件描述符打开时,您的程序是execve()
'd,其他程序也有同样的期望,所以这三个程序不应该接近exec。如果其他程序需要,您可以传递其他文件描述符(例如,gnupg有一个--status fd
参数,告诉它将机器可读状态写入某个fd),除此之外,关闭fds通常是一个好主意。说到这一点,这可以实现得简单得多:只需检查所有可能的fd号码,然后在调用exec*()
之前调用close()
。这也将捕获您的服务器套接字。
fcntl(fd, F_SETFD, (long)FD_CLOEXEC);
fd newstdin = open(...);
if(dup2(newstdin, STDIN_FILENO) != 0) { /* handle error */ }
close(newstdin);