一、FD_CLOEXEC 说明
FD_CLOSEXEC是文件描述符的标志位之一(标志位现在只有这一个)。
意思是,标志当前文件描述符,在执行exec时(exec指定的程序执行之前),是否关闭该文件描述符。
二、实例
因为要用到exec这里,我们就写两个程序。并且由于子程序的标准输出,不连接到terminal。所以我们把内容打印到文件中。
// fcntl.c主程序代码
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define CLOEXEC_ENABLE 1 // 控制是否启用CLOSEXEC标志位
int
main(int argc, char **args)
{
int fd = 0;
int pid = 0;
int fd_flag = 0;
int status = 0;
char str_fd_buf[1024] = {0};
int o_flag = 0;
o_flag = O_RDWR|O_CREAT|O_APPEND;
if (CLOEXEC_ENABLE) {
o_flag |= __O_CLOEXEC;
}
fd = open("test", o_flag, S_IRWXU);
fd_flag = fcntl(fd, F_GETFD);
if (fd_flag & FD_CLOEXEC) {
printf("FD_CLOEXEC is no\n");
} else {
printf("FD_CLOEXEC is off\n");
}
pid = fork();
if (pid == 0) {
// sub program
write(fd, "sub_said\n", strlen("sub_said\n"));
printf("sub program: fd=%d\n", fd);
sprintf(str_fd_buf, "%d", fd);
// 将打开的fd(即test文件的描述符),转成str,通过args,传递给fcntl_sub程序。
//【不可以像windows一样,直接(const char *)&fd,因为这里依赖\0来判断结束,int的高位全是0,所以会导致,传空字符串过去。fd的实际数据无法到达】
execl("fcntl_sub", str_fd_buf, NULL);
perror("execl with fail\n");
} else {
// main program
do {
wait(&status);
} while(!WIFEXITED(status)); // 等待子进程退出后跳出循环
write(fd, "main_said\n", strlen("main_said\n"));
printf("main: sub program is exited\n");
}
close(fd);
return 0;
}
// fcntl_sub.c 子程序代码
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
int
main(int argc, char **args)
{
FILE *pfile = fopen("fcntl_sub.log", "w");
int fd = -1;
const char * msg = "fcntl_sub said : I got fd\n";
fprintf(pfile, "fcntl_sub: argc %d\n", argc);
fprintf(pfile, "fcntl_sub: args[0] %s\n", args[0]);
// 将args第一个字符串通过atoi函数转化成int。获取fcntl打开的fd(即test文件)
fd = atoi(args[0]);
fprintf(pfile, "fcntl_sub: fd %d\n", fd);
// 向fd文件描述符指向的文件写入内容。
write(fd, msg, strlen(msg));
fclose(pfile);
return 0;
}
2.1 当启动CLOSEXEC时
主程序(即fcntl)输出结果
FD_CLOEXEC is no
sub program: fd=3
main: sub program is exited
test文件的内容
sub_said
main_said
fcntl_sub.log文件的内容
fcntl_sub said : I got fd
fcntl_sub: argc 1
fcntl_sub: args[0] 3
fcntl_sub: fd 3
从fcntl_sub.log中,我们会发现,fcntl_sub获取到了 fd=3。但是向fd=3的文件写入的内容到了fcntl_sub.log文件中。而没有到test文件中。因为,exec("fcntl_sub",..)执行时关闭了fork出来的子进程的fd=3的文件描述符(即test文件),然后再加载fcntl_sub的镜像,执行。所以所以,fcntl_sub中打开的fcntl_sub.log文件就打开在了描述符fd=3上。所以内容写到了fcntl_sub.log中。
2.2 当关闭CLOSEXEC时
主程序(即fcntl)输出结果
FD_CLOEXEC is off
sub program: fd=3
main: sub program is exited
test文件的内容
sub_said
fcntl_sub said : I got fd
main_said
fcntl_sub.log文件的内容
fcntl_sub: argc 1
fcntl_sub: args[0] 3
fcntl_sub: fd 3
从test文件的内容我们可以看到,这次的不同,fcntl_sub对fd=3的文件描述符写入的内容写到了test中,也就是说,在exec执行时,并没有关闭fd=3上的test的文件描述符。所以,fcntl_sub也可以使用fd=3操作test文件。
我们还可以看到fcntl.c中这段代码
pid = fork();
if (pid == 0) {
// sub program
write(fd, “sub_said\n”, strlen(“sub_said\n”));
可以看到fork得到的子程序,也得到了父进程所打开的fd=3上test文件的描述符。(所以fork会拷贝进程的文件描述符)
本文详细介绍了Linux fcntl中的FD_CLOEXEC标志的作用,它控制在执行exec时是否关闭文件描述符。通过实例分析了开启和关闭FD_CLOEXEC时,文件描述符在子进程中的状态变化,展示了exec对文件描述符的影响。
1394

被折叠的 条评论
为什么被折叠?



