#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
int fcntl(int fd, int cmd,.../*int arg*/);
- 功能:改变已经打开文件的属性
-
参数:
- 参数1:文件描述符
- 参数2:相关的选项
- 参数3(可选):总是一个整数,但是在记录锁部分,这个参数则是指向一个结构的指针
-
返回值:
- 若成功返回值依赖于cmd(见下)
- 若出错为-1
fcntl有5种功能
- 复制一个现存的描述符(cmd=F_DUPFD或F_DUPFD_CLOEXEC)
- 获得/设置文件描述符标记(cmd = F_GETFD或F_SETFD)
- 获得/设置文件状态标志(cmd = F_GETFL或F_SETFL)
- 获得/设置异步I/O所有权(cmd = F_GETOWN或F_ SETOWN)
- 获得/设置记录锁(cmd = F_GETLK , F_SETLK或F_SETLKW),详细使用见文章:javascript:void(0)
F_DUPFD | 复制文件描述符fd,新文件描述符作为函数值返回。它是尚未打开的各 描述符中大于或等于第三个参数值(取为整型值)中各值的最小值。新描述符与 fd共享同 一文件表项。但是,新描述符有它自己的一套文件描述符标志,其 FD_CLOEXEC文件描述符标志则被清除(这表示该描述符在exec时仍保持有效) 调用成功时的返回值:新的文件描述符 |
F_DUPFD_CLOEXEC | 复制文件描述符,设置与新描述符关联的FD_CLOEXEC文件描述符标志的值,返回新文件描述符 |
F_GETFD | 对应于fd的文件描述符标志作为函数值返回。当前只定义了一个文件描 述符标志FD_CLOEXEC 调用成功时的返回值:返回相应的标志 |
F_SETFD | 对于fd设置文件描述符。新标志值按第3个参数(取为整型值)设置 |
- 很多现有的与文件描述符标志有关的程序并不使用常量FD_CLOEXEC,而是将此标志设置为0(系统默认,在exec时不关闭)或1(在exec时关闭)
F_GETFL | 对应于fd的文件状态标志作为函数值返回。在说明open函数时,已说明了文件状态标志(如下图所示) 重点:但是,前5个访问方式标志(O_RDONLY、O_WRONLY、O_RDWR, O_EXEC、O_SEARCH)并不各占1位(如前所述,历史原因,前3个标志的值分别是0、1、2)。这5个值互斥,一个文件的访问方式只能取这5个值之一。因此使用F_GETFL得到结果之后还需要与屏蔽字O_ACCMODE进行按位与取得访问方式位,然后将结果与这5个值中的每一个相比较 调用成功时的返回值:返回相应的标志 |
F_SETFL | 将文件状态标志设置为第三个参数的值(取为整型值)。可以更改的几个标志是:O_APPEND、O_NONBLOCK、O_SYNC、O_DSYNC、O_RSYNC、O_FSYNC、O_ASYNC. |
F_GETOWN | 返回当前接收SIGIO和SIGURG信号的进程ID或进程组ID 返回值:如果为正值,代表得到进程ID。如果为负值(-1以外),代表得到进程组ID |
F_SETOWN | 设置接收SIGIO和SIGURG信号的进程ID或进程组ID 参数:正的arg指定一个进程ID,负的arg表示等于arg绝对值的一个进程组ID |
三、F_SETFD与F_SETFL的注意事项演示案例
下面使用F_GETFL参数判断一个文件状态标志
#include<fcntl.h> #include<stdlib.h> int main(int argc, char *argv[]) { int val; if (argc != 2) perror("usage: a.out <descriptor#>"); if ((val = fcntl(atoi(argv[1]), F_GETFL, 0)) < 0) printf("fcntl error for fd %d", atoi(argv[1])); //O_RDONLY、O_WRONLY、O_RDWR, O_EXEC、O_SEARCH这5中需要与O_ACCMODE配合判断 switch (val & O_ACCMODE) { case O_RDONLY: printf("read only"); break; case O_WRONLY: printf("write only"); break; case O_RDWR: printf("read write"); break; default: err_dump("unknown access mode"); } if (val & O_APPEND) printf(", append"); if (val & O_NONBLOCK) printf(", nonblocking"); if (val & O_SYNC) printf(", synchronous writes"); #if !defined(_POSIX_C_SOURCE) && defined(O_FSYNC) && (O_FSYNC != O_SYNC) if (val & O_FSYNC) printf(", synchronous writes"); #endif putchar(’\n’); exit(0); }
- 在修改文件描述符标志或文件状态标志时必须谨慎,先要取得现在的标志值,然后按照希望修改它,最后设置新标志值。不能只是执行 F_SETFD或F_SETFL命令,这样会关闭以前设置的标志位
自定义函数
- 我们对fcntl进行了封装,其中:
- set_fl()用于在fd上设置flags属性
- clr_fl()取消fd上的flags属性
#include <fcntl.h> void set_fl(int fd, int flags) { int val; if ((val = fcntl(fd, F_GETFL, 0)) < 0)//先得到 perror("fcntl F_GETFL error"); val |= flags; /* turn on flags */ if (fcntl(fd, F_SETFL, val) < 0)//再设置 perror("fcntl F_SETFL error"); }
#include <fcntl.h> void clr_fl(int fd, int flags) { int val; if ((val = fcntl(fd, F_GETFL, 0)) < 0)//先得到 perror("fcntl F_GETFL error"); val &= ~ flags; /* turn off flags */ if (fcntl(fd, F_SETFL, val) < 0)//再设置 perror("fcntl F_SETFL error"); }
- 例如:
- set_fl(stdout,O_SYNC); //开启同步写标志
- clr_fl(stdout,O_SYNC); //关闭同步写标志
- 注意:如果没有取得标志值就直接设置标志,意义为:设置该标志,取消其他所有标志
#include <fcntl.h>
void set_fl(int fd, int flags)
{
if (fcntl(fd, F_SETFL, flags) < 0)//再设置
perror("fcntl F_SETFL error");
}
//这种情况只设置flags,而取消其他所有的标志值
四、fcntl()在网络编程中的使用