fcntl函数

本文详细讲解了如何使用fcntl函数进行非阻塞I/O操作,包括如何通过fcntl获取和设置标准输入输出文件的访问控制属性,如O_NONBLOCK和O_ACCMODE。通过实例展示了在标准输入上实现非阻塞读取,并演示了获取和分析文件默认权限的方法。
摘要由CSDN通过智能技术生成

先前以read终端设备为例介绍了非阻塞I/O,因为STDIN_FILENO在程序启动时已经被自动打开了,所以我们需要调用open打开“/dev/tty”设备,并指定O_NONBLOCK标志。链接如下:

阻塞与非阻塞_weixin_38011893的博客-CSDN博客

现在,可以用fcntl函数改变一个已打开的文件的属性而不必重新open文件,可以重新设置读、写、追加、非阻塞等标志。

#include <unistd.h>

#include <fcntl.h>

int fcntl(int fd, int cmd);

int fcntl(int fd, int cmd, long arg);

int fcntl(int fd, int cmd, struct flock *lock);

除了F_GETFLF_SETFL命令之外,fcntl还有很多命令做其他操作,例如设置文件记录锁等。可以通过fcntl设置的都是当前进程如何访问设备或文件的访问控制属性。

非阻塞读标准输入,代码演示如下:

#include "./common/head.h"

/*功能:
 *用fcntl函数实现非阻塞I/O,从标准输入读取数据到标准输出。
 *思路:先读取打开文件的属性flag,加上想要的属性,再设置回去。
*/

int main()
{
    int flags;
    if( (flags = fcntl(STDIN_FILENO, F_GETFL)) < 0 ){    //获取标准输入文件属性
        perror("fcntl get flags");
        exit(1);
    }
    flags |= O_NONBLOCK;    //加上非阻塞属性
    if( (flags = fcntl(STDIN_FILENO, F_SETFL, flags)) < 0){    //将新属性设置回去
        perror("fcntl set flags"); 
        exit(1);
    }

    int cnt = 10;
    char buff[20] = {0};
    while(cnt--){    //轮询10次
        ssize_t n = read(STDIN_FILENO, buff, 10);
        if(n >= 0){    //读到了
            printf("read %ld bytes\n", n);
            write(STDOUT_FILENO, buff, n);    //将读到的数据打印到标准输出
            break;
        }
        if(errno != EAGAIN){    //其他错误
            perror("read STDIN_FILENO");
            eixt(1);
        }
        write(STDOUT_FILENO, "try again?\n", 11);
        sleep(1);
    }

    return 0;
}

获取标准输入、标准输出、标准错误文件默认访问控制属性,代码演示如下:

#include "./common/head.h"

/*功能:
 *执行./a.out 0或执行./a.out 1或执行./a.out 2
 *获取标准输入、标准输出、标准错误这三个文件的访问控制属性
*/

int main(int argc, char *argv[])
{
    if(argc != 2){
        printf("usage:cmd fd\n");
        return 1;
    }

#if 0
    //各个标志属性的值。ps:%#x格式打印,数值前面加上0x
    printf("O_RDONLY = %#x\n", O_RDONLY);    //0x00
    printf("O_WRONLY = %#x\n", O_WRONLY);    //0x01
    printf("O_RDWR = %#x\n", O_RDWR);        //0x02
    printf("O_ACCMODE = %#x\n", O_ACCMODE);  //0x03,正好是上面3种的组合
    printf("O_APPEND = %#x\n", O_APPEND);    //0x400
    printf("O_RDONLY = %#x\n", O_NONBLOCK);  //0x800  
#endif

    int flags;
    if( (flags = fcntl(atoi(argv[1]), F_GETFL)) < 0){    //atoi函数,将ascii码转换为数值
        perror("fcntl get flags");
        exit(1);
    }

    switch(flags & O_ACCMODE)    //O_ACCMODE宏的值为0x03, 最低两位00、01、10刚好代表只读、只写、读写,和flags作与操作,即可得到这三种状态
    {
    case O_RDONLY:
        printf("%s fd : read only", argv[1]);
        break;
    case O_WRONLY:
        printf("%s fd : write only", argv[1]);
        break;
    case O_RDWR:
        printf("%s fd : read write", argv[1]);
        break;
    defalut:
        printf("invalid access mode\n");
        break;
    }

    //flags和其他标志做&操作,不为0就代表该文件有此标志的访问控制属性
    if(flags & O_NONBLOCK)    printf(", nonblock");
    if(flags & O_APPEND)      printf(", append");

    putchar(10);    //最后输出换行    

    return 0;
}

结果:

$ ./a.out 0

$ 0 fd : read write 

$ ./a.out 1

$ 1 fd : read write 

$ ./a.out 2

$ 2 fd : read write 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值