Linux fcntl中FD_CLOEXEC 作用

本文详细介绍了Linux fcntl中的FD_CLOEXEC标志的作用,它控制在执行exec时是否关闭文件描述符。通过实例分析了开启和关闭FD_CLOEXEC时,文件描述符在子进程中的状态变化,展示了exec对文件描述符的影响。

一、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会拷贝进程的文件描述符)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值