阿牧路泽

哪有那么多坚强,无非是死扛罢了
  博客园  :: 首页  :: 新随笔  :: 联系 :: 管理

9、【Linux系统编程】fcntl函数

Posted on 2018-08-07 15:47  阿牧路泽  阅读(166)  评论(0编辑  收藏  举报

  上一篇博客我们以read终端设备为例介绍了非阻塞I/O,为什么我们不直接对STDIN_FILENO做非阻塞read,而要重新open一遍/dev/tty呢?因为STDIN_FILENO在程序启动时已经被自动打开了,而我们需要在调用open时指定O_NONBLOCK标志。这里介绍另外一种办法,可以用fcntl函数改变一个已打开的文件的属性,可以重新设置读、写、追加、非阻塞等标志(这些标志称为File Status Flag),而不必重新open文件。头文件及函数原型:

1 #include <unistd.h>
2 #include <fcntl.h>
3 
4 int fcntl(int fd, int cmd);
5 int fcntl(int fd, int cmd, long arg);
6 int fcntl(int fd, int cmd, struct flock *lock);

  这个函数和open一样,也是用可变参数实现的,可变参数的类型和个数取决于前面的cmd参数。下面的例子使用F_GETFL和F_SETFL这两种fcntl命令改变STDIN_FILENO的属性,加上O_NONBLOCK选项,实现前一博客 “非阻塞读终端”同样的功能。

 1 #include <unistd.h>
 2 #include <fcntl.h>
 3 #include <errno.h>
 4 #include <string.h>
 5 #include <stdlib.h>
 6 #include <iostream>
 7 using namespace std;
 8 
 9 #define MSG_TRY "try again\n"
10 
11 int main(void)
12 {
13     char buf[10];
14     int n;
15     int flags;
16     flags = fcntl(STDIN_FILENO, F_GETFL);//获取标准输入的标志位
17     flags |= O_NONBLOCK;//增加非阻塞状态标志
18     if (fcntl(STDIN_FILENO, F_SETFL, flags) == -1)//写回标准输入标志位
19     {
20         cout << "fcntl" << endl;
21         return 1;
22     }
23 tryagain:
24     n = read(STDIN_FILENO, buf, 10);
25     if (n < 0) {
26         if (errno == EAGAIN) {
27             sleep(1);
28             write(STDOUT_FILENO, MSG_TRY, strlen(MSG_TRY));
29             goto tryagain;
30         }
31         cout << "read stdin" << endl;
32         return 1;
33     }
34     write(STDOUT_FILENO, buf, n);
35     return 0;
36 }