fcntl()系统调用

五一3天小长假,在家里悠闲度过了。基本没学习,昨天下午回到深圳,研究了一下fcntl()系统调用。

1. 函数介绍

函数fcntl()用于修改某个文件描述符的属性,函数原型为:

#include <unistd.h>
#include <fcntl.h>

int fcntl(int fd, int cmd, ... /* arg */ );

第1个参数fd为待修改属性的文件描述符,第2个参数cmd为对应的操作命令,第3个参数为cmd的参数。
常见的cmd命令有:

F_DUPFD     //复制文件描述符,跟dup()函数功能一样
F_GETFD     //获取文件描述符标志
F_SETFD     //设置文件描述符标志
F_GETFL     //获取文件状态
F_SETFL     //设置文件状态

函数执行失败,将返回-1并设置errno全局变量来指明错误。
不同的cmd其返回值不同: 若是设置文件属性,成功返回0失败返回-1;
若是读取文件属性,成功返回该属性值,失败返回-1。

2. 函数使用

2.1 F_DUPFD赋值文件描述符

fcntl()函数中cmd若使用F_DUPFD命令则是复制文件描述符,返回的值是新的文件描述符,该文件描述符同样指向原文件,具有特点有:
1) 大于或者等于指定的最小可用的文件描述符。”指定”是在函数的第三个参数指定的。
2) 和原文件相同方式的打开文件(包括管道)
3) 两个文件描述符共享一个文件指针
4) 两个文件描述符共享同一文件状态标志
5) 新的文件描述符关联的close-on-exec标志在各execX()函数簇中还是保持打开状态

int main(void)
{
    const char* ptr = "Hello, funtl()\n";
    int fd, new_fd;

    fd = open("tmp.file", O_WRONLY | O_CREAT, 0666);
    if (fd < 0)
    {
        perror("open");
        exit(EXIT_FAILURE);
    }

    //赋值文件描述符,参数3设置为0,那么new_fd为3
    new_fd = fcntl(fd, F_DUPFD, 0);
    printf("fd = %d, new_fd = %d\n", fd, new_fd);
    printf("write %d bytes to fd\n", write(fd, ptr, strlen(ptr)));
    printf("write %d bytes to new_fd\n", write(new_fd, ptr, strlen(ptr)));

    close(fd);
    close(new_fd);

    system("cat tmp.file");

    return 0;
}

运行结果:
这里写图片描述

2.2 F_GETFD / F_SETFD操作close-on-exec

首先了解close-on-exec是什么?每个文件描述符都有一个close-on-exec标志,这个标志的具体作用是体现在其它进程调用execX()函数簇时,是否关闭在这之前的文件描述符。F_GETFD命令获取文件描述符关联的close-on-exec标志。如果close-on-exec低序位为0,文件将在execX()函数执行期间保持打开状态,否则文件在执行execX()函数期间是关闭的。默认情况下是打开的,则允许在execX()函数簇代码中访问原来打开的文件描述符。
F_SETFL命令用于设置与文件描述符相关的close-on-exec标志,设置的值为fcntl的第3个参数。
若设置为1,即FD_CLOEXEC,

/* for F_[GET|SET]FL */
#define FD_CLOEXEC  1   /* actually anything with low bit set goes */

那么子进程的execX()函数簇中不可以使用该文件描述符,代码示例在http://blog.csdn.net/qq_29344757/article/details/70316536#t13讲过。

2.3 F_GETFL / F_SETFD设置文件描述符状态

F_GETFL命令用于获取文件状态标志,F_SETFL将文件状态标志设置为funtl()的第3个参数。也就是说,它不能设置读写属性(O_RDWR、O_WRONLY、O_RDONLY),设置文件状态属性,如阻塞/非阻塞、追加(O_APPEND)。

/*
    实验证明:
    F_SETFD是设置文件的close-on-exec标志
    F_SETFD是设置文件状态属性,如阻塞/非阻塞、追加(O_APPEND)
*/

int pre_test(int flag)
{
    int accmode;

    accmode = flag & O_ACCMODE;     //获取文件的读写属性需要这么操作
    if (accmode == O_RDONLY)
        printf("read only");
    else if (accmode == O_WRONLY)
        printf("write only");
    else if (accmode == O_RDWR)
        printf("read write");
    else
        printf("unknown mode");

    if (flag & O_APPEND)
        printf(", append");
    if (flag & O_NONBLOCK)
        printf(", nonblocking");

    printf("\n");

    return 0;
}

int main(int argc, char** argv)
{
    int flag;
    int fd;

    fd = open("./tmp.file", O_RDONLY);

    flag = fcntl(fd, F_GETFL);
    if (flag < 0)
    {
        perror("fcntl");
        exit(EXIT_FAILURE);
    }

    pre_test(flag);

    fcntl(fd, F_SETFL, flag | O_NONBLOCK | O_APPEND);
    flag = fcntl(fd, F_GETFL);

    pre_test(flag);

    return 0;
}

运行结果:
这里写图片描述

F_SETFD和F_SETFL存在区别:
F_SETFD仅更改该文件描述符的信息,而F_SETFL则是更改与该文件相关的所有描述符。比如复制了某个文件描述符后,若使用F_SETFD修改close-on-exec标志,那么只是修改该文件描述符信息,若使用F_SETFL修改将修改原文件和拷贝文件描述符的状态信息。

水平有限,上述结论可能还有误,先总结这么多吧,

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值