文件描述符标志

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了文件描述符标志相关的知识,希望对你有一定的参考价值。

文件描述符标志(目前就只有一个close-on-exec):

  它仅仅是一个标志,当进程fork一个子进程的时候,在子进程中调用了exec函数时就用到了这个标志。意义是执行exec前是否要关闭这个文件描述符。

  close-on-exec是一个进程所有文件描述符(文件句柄)的位图标志,每个比特位代表一个打开的文件描述符的标志位,用于确定在调用系统调用exec()时是否需要关闭文件的句柄。当一个进程使用fork()函数创建了一个子进程时,通常在该子进程中调用execve()函数来加载执行另一个新的程序。此时子程序讲完全被新程序替换掉,并在子进程中开始执行新程序。若一个文件描述符在close-on-exec中的对应比特位被设置,那么在执行execve()时,该描述符将被关闭,否则该描述符将始终处于打开的状态,也就是说close-on-exec的默认状态是没有被设置的。

技术分享

close-on-exec标志由如下用途:

1. 如果调用了exec(),应该关闭指定的套接字。

2. 一般会调用exec执行另一个程序,此时会用全新的程序替换子进程的正文、数据、堆和栈等数据。此时保存文件描述符的变量当然也不存在了,我们就无法关闭无用的文件描述符了。所以通常我们会fork进程后在子进程中执行close关掉无用的文件描述符,然后在执行exec。

例:父进程代码

/* Parent Process */
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <sys/wait.h>
 
int main()
{
    int fd = open("test.txt", O_RDWR | O_APPEND);
    if(fd == -1)
    {
        printf("the file test.txt open failed! the fd = %d\\n", fd);
        execl("/bin/touch", "touch", "test.txt", (char *)NULL);
        return 0;
    }
    else
    {
        printf("the file test.txt open success! the fd = %d\\n", fd);
    }
 
    printf("fork...\\n");
 
    //什么也不写,相当于默认fcntl(fd, F_SETFD, 0),即用execl执行子进程时
    //不打开“执行时关闭”标志位FD_CLOEXEC,此时子进程可以向test.txt写入字符串
 
    //下面的三句话控制父进程的文件描述符在子进程中是否被关闭
    //fcntl(fd, F_SETFD, 1);
    int flags = fcntl(fd, F_FETFD);
    fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
 
    char *str = "The Parent Process Writted!\\n";
 
    pid_t pid = fork();
    if(pid == 0)
    {
        printf("***execl child***\\n");
        execl("child", "./child", &fd, NULL);
        printf("*****************\\n");
    }
 
    //等待子进程结束
    wait(NULL);
 
    ssize_t write_bytes = write(fd, (void *)str, strlen(str));
    if(write_bytes == -1)
    {
        printf("The Parent Process Write To fd: %d Failed!\\n", fd);
    }
 
    close(fd);
    return 0;
}

子进程代码:

/* Child Process */
#include <stdio.h>
#include <unistd.h>
#include <string.h>
 
int main(int argc, char *argv[])
{
    printf("argc = %d\\n", argc);
 
    if(argv[1] == NULL)
    {
        printf("There is no Parameter!\\n");
        return 0;
    }
 
    int fd = *argv[1];
    printf("child fd = %d\\n", fd);
 
    char *str = "Child Process Writted!\\n";
    ssize_t write_bytes = write(fd, (void *)str, strlslen(str));
 
    if(write_bytes == -1)
    {
        printf("The child Process write To fd: %d Failed\\n", fd);
    }
 
    close(fd);
    return 0;
}

两段代码通过fcntl函数设置fd的文件描述标志位,控制父进程中的文件描述符在子进程中是否被关闭。同时注意,这里的FD_CLOEXEC标识符,只针对exec系列的函数有效,如果子进程直接在当前例程的pid == 0的判断里面write,而不是通过execl一个新的例程write文件,这是FD_CLOEXEC标识符是不起作用的。

转载:http://www.cnblogs.com/stemon/p/5242547.html

以上是关于文件描述符标志的主要内容,如果未能解决你的问题,请参考以下文章

I2C 文件描述符上的 I2C 总线可写/可读标志

包——基本概念,自定义包,创建包,导出包中的标志符

Java 虚拟机原理Class 字节码二进制文件分析 四 ( 字段表数据结构 | 字段表详细分析 | 访问标志 | 字段名称 | 字段描述符 | 属性项目 )

如何使用带有 Ninja 生成器的 CMake 将修饰符标志传递给存档文件(ar)

linux套接字或者文件描述符的未读取得字节数FIONREAD,MSG_PEEK标志

epoll使用详解