zoukankan      html  css  js  c++  java
  • APUE学习笔记——3.文件共享与fcntl介绍

    基本概念

    内核使用3个数据结构描述一个打开的文件进程表、文件表、V节点表
    首先了解3种数据结构的概念
        1 进程表
            每一个进程有一个进程表。进程表里是一组打开的文件描述符,如标准输入0,标准输出1,标准错误2...
        2 文件表
            进程打开一个文件时,内核就为该文件创建一个文件表。
            进程表对文件表一般是 一对多的关系    文件表对文件描述符也是一对多的关系(可能多个文件描述符指向同一文件表)
    (这里解释下为什么进程表和文件表一对多的关系只是一般情况下,有什么特殊情况呢?  当父进程fork一个子进程时,复制了它的进程表,导致多个进程表对一个文件表)
             文件表中包含了文件状态标志、当前偏移量、和V-node pointer表项
                文件状态标志如:read,  write,  append,  sync, nonblocking等等
                偏移量好理解,就不多解释了(它在write时会变化)
                V-node pointer就是指向V-node表的指针
            
        3 V节点表(Linux只有i节点表)
            每一个没打开的文件有一个V节点表。V-node table实际上跟进程关系不大,主要跟被打开的文件相关。一个打开的文件只有一个v-node表,所有打开它的进程共用此表
            文件表对V节点表示多对一的关系。
            V-node表主要是描述了文件信息、数据的访问入口

    一个进程打开多个文件


        如《APUE E3rd》的Figure3.7所示,一个进程打开多个文件。
        文件描述符0和1各通过一个文件表打开一个文件
        注:可能文件描述符0和3指向同一个文件表

    多个进程打开一个文件

        
        如《APUE E3rd》中figure 3.8所示,两个进程打开同一个文件。
        两个进程使用的文件表都是进程独有的。也就是说一个文件表虽然是内核维护的,但它至属于某一个特定进程。

    fcntl

        功能描述:通过文件描述符来操作文件的属性。
        形式:
    #include <fcntl.h>
    int fcntl(int fd,int cmd,... /* intarg */ );
                Returns: depends on cmd if OK (see following),−1 on error

        描述:fcntl()可以改变已打开文件的性质。参数fd是一打开的文件描述符,cmd是特定的命令,第三个参数是否存在取决于cmd的值。第三个参数如果存在一般为整形,也可能是struct flock *类型的结构体指针。
        返回值:返回值是否存在也取决于cmd,一般错误返回-1,F_DUPFD , F_GETFD , F_GETFL以及F_GETOWN会返回文件描述符或者文件的一些属性。
        一般在下面五种情况下使用fcntl()函数
        1. 复制一个已存在的文件描述符(cmd=F_DUPFD、F_DUP、FD_CLOEXEC)
        2. 取得/设置已存在文件描述符的标志(cmd=F_GETFD、F_SETFD)
        3. 取得/设置已存在文件描述符的状态标志(cmd=GETFL、SETFL
        4. 取得/设置异步I/O时文件的所有权(cmd=GETOWN、SETOWN+)
        5. 取得/设置异步锁(cmd=GETLK、SETLK、SETLKW)
        文件标志位:进程表中每一条记录都对应了一个文件描述符的fd标志位和指向文件表的指针,fd标志位目前只定义了FD_CLOEXEC一项。因此,fd标志位就是FD_CLOEXEC

    cmd参数

    F_DUPFD:
        复制一个已存在的文件描述符,新文件描述符作为函数的返回值,其取值一般是不小于3且还没被打开的文件描述符。新旧两个文件描述符共享文件表,但是两个描述符有不同的fd标志位(进程表中每一个表项记录了一个文件描述符的fd标志位和指向文件表的指针)。使用F_DUPFD时,fd标志位的FD_CLOEXEC将被清零①  
    F_DUPFD_CLOEXEC
        复制一个已存在的文件描述符,与F_DUPFD不同之处在于其设置了FD_CLOEXEC。也就是在使用exec是文件被关闭。
    F_GETFD
        返回文件标志位,目前文件标志位只定义了FD_CLOEXEC,因此返回值就是FD_CLOEXEC的值。
    F_SETFD
        设置文件标志位(即设置FD_CLOEXEC),设置的值在第三个参数。
    F_GETFL
        返回该文件描述符对应的文件状态标志位file status flag。文件状态标志位主要有O_RDONLY、O_WRONLY,本文后面进一步讨论。
    F_SETFL
        设置文件状态标志。只有O_APPEND、O_NONBLOCK、O_SYNC、O_DSYNC、O_RSYNC、O_FSYNC、O_ASYNC其中状态标志可以被更改(设置)。
    F_GETOWN
        取得当前正在接收SIGIO或者SIGURG信号的进程id或进程组id,进程组id返回的是负值(arg被忽略)
    F_SETOWN
        设置将接收SIGIO和SIGURG信号的进程id或进程组id,进程id和进程组id通过第三个参数arg传入(只能传一个,要么进程id,要么进程组id),arg为正值表示传入的是进程id,arg为负值则传入的是进程组id。
    F_GETLK    
        取得文件的锁定状态,如果被锁定了,则将锁定信息重写到第三个参数arg(一个指向flock的结构体的指针)。如果未被锁定状态,则除了struct flock的l_type被设置为F_UNLCK外,其他成员不变。 
    F_SETLK    
        通过第三个参数arg(struct flock*)锁定文件。如果read lock和write lock设置失败,则返回EACCES  or  EAGAIN
    F_SETLKW   
       类似F_SETLK,不同的是当设置锁发生阻塞时,它会等待(W是wait的意思),直至设置锁完成


    文件状态标志


        O_RDONLY , O_WRONLY与O_RDWR 还有后面的O_EXEC、O_SEARCH并不是每一项占一位的,因此,在获取文件状态时,为取得文件当前的存取模式,需要用O_ACCMODE与F_GETFL操作返回的值进行与运算
        关于文件标志位的值,如下在系统头文件fcntl.h(我的熊中是/usr/include/i386-linux-gnu/bits/fcntl)
    /* open/fcntl - O_SYNC is only implemented on blocks devices and on files
       located on a few file systems.  */
    #define O_ACCMODE          0003
    #define O_RDONLY             00
    #define O_WRONLY             01
    #define O_RDWR               02
    #define O_APPEND          02000
    #define O_NONBLOCK        04000
    #define O_NDELAY        O_NONBLOCK
    #define O_SYNC         04010000
    #define O_FSYNC          O_SYNC
    #define O_ASYNC          020000


    可以看到《APUE》中关于O_SYNC的讨论实际上代码中已经有给出注释。

    结构体指针 struct flock*

    struct flock {
            short  l_type; /* F_RDLCK, F_WRLCK, or F_UNLCK */
            short  l_whence; /* SEEK_SET, SEEK_CUR, or SEEK_END */
            off_t  l_start;  /* offset in bytes, relative to l_whence */
            off_t  l_len; /* length, in bytes; 0 means lock to EOF */
            pid_t  l_pid; /* returned with F_GETLK */
    };
    
       


    注解:
        FD_CLOEXEC为0时,表示使用exec函数族时文件描述符fd会被传入exec()创建的新进程,如果FD_CLOEXEC为1,则文件被关闭




  • 相关阅读:
    Redis
    元类 metaclass
    聊一聊 Django 中间件
    Django rest framework
    聊一聊python的单例模式
    Django-admin管理工具
    MongoDB
    Beautifulsoup
    三、模型(一)
    九、Python发送QQ邮件(SMTP)
  • 原文地址:https://www.cnblogs.com/Windeal/p/4284663.html
Copyright © 2011-2022 走看看