fctrl:改变已打开文件的属性
原型:int fcntl(int fd, int cmd, ... /* arg */ );
cmd为以下属性:
1. 复制一个现有的描述符(cmd=F_DUPFD或F_DUPFD_CLOEXEC).
2. 获得/设置文件描述符标记(cmd=F_GETFD或F_SETFD).
3. 获得/设置文件状态标记(cmd=F_GETFL或F_SETFL).
4. 获得/设置异步I/O所有权(cmd=F_GETOWN或F_SETOWN).
5. 获得/设置记录锁(cmd=F_GETLK , F_SETLK或F_SETLKW).
一、 复制一个现有的描述符(cmd=F_DUPFD).
F_DUPFD 返回一个如下描述的(文件)描述符:
·大于或等于arg中的最小的的一个可用的描述符
·与原始操作符一样的某对象的引用
·如果对象是文件(file)的话,则返回一个新的描述符,这个描述符与arg共享相同的偏移量(offset)
·相同的访问模式(读,写或读/写)
·相同的文件状态标志(如:两个文件描述符共享相同的状态标志)
实际上调用dup(oldfd);
等效于
fcntl(oldfd, F_DUPFD, 0);
而调用dup2(oldfd, newfd);
等效于
close(oldfd);
fcntl(oldfd, F_DUPFD, newfd);
F_DUPFD_CLOEXEC在F_DUPFD 的基础上与新的文件描述符结合在一起的close-on-exec标志被设置成交叉式访问execve( 2)的系统调用
二、 获得/设置文件描述符标记(cmd=F_GETFD或F_SETFD).
F_GETFD 取得与文件描述符fd的close-on-exec标志,类似FD_CLOEXEC。如果返回值和FD_CLOEXEC进行与运算结果
是0的话,文件保持交叉式访问exec(),否则如果通过exec运行的话,文件将被关闭(arg 被忽略)
F_SETFD 设置close-on-exec标志,该标志以参数arg的FD_CLOEXEC位决定,应当了解很多现存的涉及文件描述符标志
的程序并不使用常数 FD_CLOEXEC,而是将此标志设置为0(系统默认,在exec时不关闭)或1(在exec时关闭) 。
在修改文件描述符标志或文件状态标志时必须谨慎,先要取得现在的标志值,然后按照希望修改它,最后设置新标志值
。不能只是执行F_SETFD或F_SETFL命令,这样会关闭以前设置的标志位。
三、获得/设置文件状态标记(cmd=F_GETFL或F_SETFL).
F_GETFL 取得fd的文件状态标志,如同下面的描述一样(arg被忽略),在说明open函数时,已说明了文件状态标志。不
幸的是,三个存取方式标志 (O_RDONLY , O_WRONLY , 以及O_RDWR)并不各占1位。(这三种标志的值各是0 , 1
和2,由于历史原因,这三种值互斥 — 一个文件只能有这三种值之一。) 因此首先必须用屏蔽字O_ACCMODE相与
取得存取方式位,然后将结果与这三种值相比较。
F_SETFL 设置给arg描述符状态标志,
O_RDONLY:只读
O_WRONLY:只写
O_RDWR:可读可写
O_CREAT:若此文件不存在则创建它。使用此选项时需要提供第三个参数mode
,表示该文件的访问权限
O_EXCL:如果同时指定了O_CREAT
,并且文件已存在,则出错返回
O_NOCTTY:通知linux系统,这个程序不会成为这个端口的控制终端
O_TRUNC:若文件存在,则清空文件,属性不变
O_APPEND:在每次写之前,都讲标志位移动到文件的末端
O_ASYNC:异步I/O驱动
O_DIRECT:直接进行文件IO,而系统不进行缓存,会影响文件读写速度,但可能对用户内存影响较小
O_NOATIME:不记录文件访问的时间,可用于机器IO负载高或是CPUWAIT高的情况
O_NONBLOCK:非阻塞方式
四、获得/设置异步I/O所有权(cmd=F_GETOWN或F_SETOWN).
F_GETOWN 取得当前正在接收SIGIO或者SIGURG信号的进程id或进程组id,进程组id返回的是负值(arg被忽略)
F_SETOWN 设置将接收SIGIO(异步IO信号)和SIGURG(紧急信号)的进程id或进程组id,进程组id通过提供负值的a rg来说明(arg绝对值的一个进程组ID),否则arg将被认为是进程id
外加小知识:SIGURG,传输层协议使用带外数据(out-of-band,OOB)来发送一些重要的数据,如果通信一方有重要 的数据需要通知对方时,协议能够将这些数据快速地发送到对方。为了发送这些数据,协议一般不使用与普通数据 相同的通道,而是使用另外的通道。linux系统的套接字机制支持低层协议发送和接受带外数据。但是TCP协议没有 真正意义上的带外数据。为了发送重要协议,TCP提供了一种称为紧急模式(urgent mode)的机制。TCP协议在 数据段中设置URG位,表示进入紧急模式。接收方可以对紧急模式采取特殊的处理。很容易看出来,这种方式数据 不容易被阻塞,并且可以通过在我们的服务器端程序里面捕捉SIGURG信号来及时接受数据。这正是我们所要求的 效果。由于TCP协议每次只能发送和接受带外数据一个字节,所以,我们可以通过设置一个数组,利用发送数组下 标的办法让服务器程序能够知道自己要监听的端口以及要连接的服务器IP/port。由于限定在1个字节,所以我们最 多只能控制255个port的连接,255个内网机器(不过同一子网的机器不会超过255个),同样也只能控制255个监 听端口,不过这些已经足够了。
五、获得/设置(非阻塞、阻塞)记录锁(cmd=F_GETLK , F_SETLK或F_SETLKW).
F_GETLK 用来检测是否有某个已存在的锁会妨碍将新锁授予调用进程,如果没有这样的锁,lock所指向的flock结构中的
l_type成员就会被置成F_UNLCK,否则已存在的锁的信息将会写入lock所指向的flock结构中
F_SETLK 获取(l_type为F_RDLCK或F_WRLCK)或释放(l_type为F_UNLCK)由lock指向flock结构所描述的锁,如果无 法获取锁时,该函数会立即返回一个EACCESS或EAGAIN错误,而不会阻塞
F_SETLKW F_SETLKW和F_SETLK的区别是,无法设置锁的时候,调用线程会阻塞到该锁能够授权位置。
这里需要注意的是,用 F_GETLK 测试能否建立一把锁,然后接着用 F_SETLK 或 F_SETLKW 企图建立一把锁,由于这两者
不是一个原子操作,所以不能保证两次fcntl之间不会有另外一个进程插入并建立一把相关的锁,从而使一开始的测
试情况无效。所以一般不希望上锁时阻塞,会直接通过调用F_SETLK,并对返回结果进行测试,以判断是否成功
建立所要求的锁。