fcntl函数用法——操纵文件描述符状态

fcntl函数:操纵文件描述符,改变已经打开的文件的属性
int fcntl(int fd, int cmd, ... //arg  );
cmd选项:
一、复制文件描述符:F_DUPFD
二、更改设置文件描述标志:F_GETFD 、F_SETFD  文件描述符标志,是体现进程的文件描述符的状态.
当前只定义了一个文件描述符标志FD_CLOEXEC。
   0: exec时不关闭已经打开的文件描述符
   1: exec时关闭已经打开的文件描述符

三、获取或者设置文件状态标识:F_GETFL、 F_SETFL(读写追加阻塞等等)
    文件状态标签中的标志可分为三类:访问方式、打开时标志和I/O操作方式。
 1. 访问方式 访问方式指明允许文件描述字用于读、写或两者兼之,包括O_RDONLY、O_WRONLY和O_RDWR。
这些访问方式在文件被打开时选定,之后便不能再改变。
 2、打开时标志指明打开文件时影响open()行为的一些选项。这些选项一旦文件打开就不保留,
但有一个例外是O_NONBLOCK,因为O_NONBLOCK同时也是一个I/O操作方式,故此标志被保留例如:O_CREAT
 3、I/O操作方式:I/O操作方式影响使用文件描述字进行输入输出操作的工作方式。这些标志由open()设置,
之后可以用fcntl()获取和改变。O_APPEND、O_NONBLOCK、O_SYNC等
四、设置获取文件锁:F_GETLK、F_SETLK,F_SETLKW

 1 #include<unistd.h>
 2 #include<sys/types.h>
 3 #include<sys/stat.h>
 4 #include<fcntl.h>
 5 #include<stdlib.h>
 6 #include<stdio.h>
 7 #include<errno.h>
 8 #include<string.h>
 9 #define ERR_EXIT(m)
10     do
11     {
12         perror(m);
13         exit(EXIT_FAILURE);
14     }while(0)  //宏要求一条语句
15 void set_flags(int fd,int flags);
16 void clr_flags(int fd,int flags);
17 int main(int argc,char*argv[])
18 {
19     char buf[1024]={0};
20     int ret;
21 /*    flags=fcntl(0,F_GETFL,0);//先获取标准输入的标志
22     if(flags==-1)
23         ERR_EXIT("fcntl get flags error");
24     ret=fcntl(0,F_SETFL,flags|O_NONBLOCK);//将标准输入设置为非阻塞,默认对读是阻塞的。不更改其他状态
25     if(ret==-1)
26         ERR_EXIT("fcntl set flags error");
27 */    set_flags(0,O_NONBLOCK);//设置非阻塞,直接返回   (EAGIAN)read error: Resource temporarily unavailable(资源暂且不可用),如果是socket,会返回EWOUDBOCK
28     //clr_flags(0,O_NONBLOCK);//清除
29     ret=read(0,buf,1024);//标准输入读,read标准输入0默认阻塞(文件状态标志)
30     if(ret==-1)
31         ERR_EXIT("read error");
32     printf("buf=%s
",buf);
33     return 0;
34 }
35 void set_flags(int fd,int flags)
36 {
37     int val;
38     val=fcntl(fd,F_GETFL,0);//先获取标准输入的标志
39     if(val==-1)
40         ERR_EXIT("fcntl get flags error");
41     val |=flags;
42     if(fcntl(fd,F_SETFL,val)<0)
43         ERR_EXIT("fcntl set flags error");
44 }
45 void clr_flags(int fd,int flags)//清除状态
46 {
47     int val;
48     val=fcntl(fd,F_GETFL,0);//先获取标准输入的标志
49     if(val==-1)
50         ERR_EXIT("fcntl get flags error");
51     val&=(~flags);//原状态中与上 flags 的反
52     if(fcntl(fd,F_SETFL,val)<0)
53         ERR_EXIT("fcntl set flags error");
54 }

下面的例子讲解fcntl更改设置文件描述标志:

 1 //hello.c
 2 #include<unistd.h>
 3 #include<stdio.h>
 4 //hello程序打印程序环境变量
 5 extern char** environ;//指针的指针,指向一个指针数组 environ-->[...]数组中每一项指向一个环境信息。例如"TERM=VI00","SHELL=/bin/bash"
 6 int main(void)
 7 {
 8     printf("hello pid=%d
",getpid());
 9     //打印环境变量
10     int i;
11     for(i=0;environ[i]!=NULL;i++)
12     {
13         printf("%s
",environ[i]);
14     }
15     return 0;
16 }
17 
18 //ececlp.标准输出在execlp中已经关闭,无法使用
19 #include<unistd.h>
20 #include<sys/types.h>
21 #include<stdlib.h>
22 #include<stdio.h>
23 #include<errno.h>
24 #include<fcntl.h>
25 #define ERR_EXIT(m)
26     do
27     {
28         perror(m);
29         exit(EXIT_FAILURE);
30     }while(0)  //宏要求一条语句
31 int main()
32 {
33     printf("Entering main...
");
34     int flag=fcntl(1,F_GETFD);
35     int ret=fcntl(1,F_SETFD,flag|FD_CLOEXEC);//标准输出EXEC位置1
36     if(ret==-1)
37         perror("fcntl");
38     //使用exec执行的程序里,此描述符被关闭,不能再使用它
39     execlp("./hello","hello",NULL);//ececlp替换是成功的,但是标准输出EXEC位已经被置位,所以hello无法输出。
40 /*输出结果
41 Entering main...
42 */
43     printf("Exiting main...
");//不输出了
44     return 0;
45 }
原文地址:https://www.cnblogs.com/wsw-seu/p/8289741.html