一、fcntl()函数
1. 函数的原型
- 函数说明:fcntl()用来操作文件描述词的一些特性
- 函数功能:可以改变已经打开文件的性质
- 参数说明:
- fd:代表欲设置的文件描述符
- cmd:代表欲操作的指令。针对cmd的值,fcntl能够接受第三个参数int arg。有以下几种情况:
- F_DUPFD:用来查找大于或等于参数 arg 的最小且仍未使用的文件描述符,并且复制参数 fd 的文件描述符。执行成功则返回新复制的文件描述符。请参考dup2()。复制文件描述符,新的文件描述符作为函数返回值返回。
- F_GETFD:获取文件描述符,通过第三个参数设置
- F_SETFD:设置文件描述符,通过第三个参数设置
- F_GETFL/F_SETFL:
- 取得/设置文件状态标志,通过第三个参数设置
- 可以更改的几个标志是:O_APPEND、O_NONBLOCK、SYNC、O_ASYNC(O_RDONLY、O_WRONLY和O_RDWR不适用)
- F_GETLK 取得文件锁定的状态。
- F_SETLK 设置文件锁定的状态。此时flcok 结构的l_type 值必须是F_RDLCK、F_WRLCK或F_UNLCK。如果无法建立锁定,则返回-1,错误代码为EACCES 或EAGAIN。
- F_SETLKW F_SETLK 作用相同,但是无法建立锁定时,此调用会一直等到锁定动作成功为止。若在等待锁定的过程中被信号中断时,会立即返回-1,错误代码为EINTR。
- 参数lock指针为flock 结构指针,定义在下面。
- 返回值:
- 成功则返回0,若有错误则返回-1,错误原因存于errno。
- 常见的功能:
- 复制一个现存的描述符,新文件描述符作为函数返回值(cmd = F_DUPFD)
- 获得/设置文件描述符标志(cmd = F_GETFD 或 F_SETFD)
- 获得/设置文件状态标志(cmd = F_GETFL 或 F_SETFL)
- 获得/设置文件锁(cmd = F_SETLK、cmd= F_GETLK、F_SETLKW)
- 文件记录锁是fcntl函数的主要功能。
- 记录锁:实现只锁文件的某个部分,并且可以灵活的选择是阻塞方式还是立刻返回方式
- 当fcntl用于管理文件记录锁的操作时,第三个参数指向一个struct flock *lock的结构体
- l_type 有三种状态:
- F_RDLCK 建立一个供读取用的锁定
- F_WRLCK 建立一个供写入用的锁定
- F_UNLCK 删除之前建立的锁定
- l_whence 也有三种方式:
- SEEK_SET 以文件开头为锁定的起始位置。
- SEEK_CUR 以目前文件读写位置为锁定的起始位置
- SEEK_END 以文件结尾为锁定的起始位置。
注意事项:
- short_l_type用来指定设置共享锁(F_RDLCK,读锁)还是互斥锁(F_WDLCK,写锁)。
当short_l_type的值为F_UNLCK时,传入函数中将解锁。
每个进程可以在该字节区域上设置不同的读锁。
但给定的字节上只能设置一把写锁,并且写锁存在就不能再设其他任何锁,且该写锁只能被一个进程单独使用。
这是多个进程的情况。
单个进程时,文件的一个区域上只能有一把锁,若该区域已经存在一个锁,再在该区域设置锁时,新锁会覆盖掉旧的锁,无论是写锁还时读锁。 - l_whence,l_start,l_len三个变量来确定给文件上锁的区域。
l_whence确定文件内部的位置指针从哪开始,l_star确定从l_whence开始的位置的偏移量,两个变量一起确定了文件内的位置指针先所指的位置,即开始上锁的位置,然后l_len的字节数就确定了上锁的区域。
特殊的,当l_len的值为0时,则表示锁的区域从起点开始直至最大的可能位置,就是从l_whence和l_start两个变量确定的开始位置开始上锁,将开始以后的所有区域都上锁。
为了锁整个文件,我们会把l_whence,l_start,l_len都设为0。
2. 案例
io.c
file_append.c
使用设置文件状态标志,将文件标志的状态更改成为O_APPEND。也可清除相关的文件状态标志,就会出现被覆盖的现象。更改为O_APPEND的运行结果如下:
二、ioctl()函数
1. ioctl()函数
ioctl是设备驱动程序中对设备的I/O通道进行管理的函数。所谓对I/O通道进行管理,就是对设备的一些特性进行控制,例如串口的传输波特率、马达的转速等等。
- 函数说明:
- ioctl函数是文件结构中的一个属性分量,就是说如果你的驱动程序提供了对ioctl的支持,用户就能在用户程序中使用ioctl函数 控制设备的I/O通道。
- 此函数可以说是 I/O操作的杂物箱。不能用前面说的函数表示的 I/O 操作通常都能用 ioctl 表示。
- 终端 I/O 是 ioctl 的最大使用方面,主要用于设备 I/O 控制
- 函数功能:
- 控制I/O设备 ,提供了一种获得设备信息和向设备发送控制参数的手段。
- 用于向设备发控制和配置命令 ,有些命令需要控制参数,这些数据是不能用read / write 读写的,称为Out-of-band数据。
- 也就是说,read / write 读写的数据是in-band数据,是I/O操作的主体,而ioctl 命令传送的是控制信息,其中的数据是辅助的数据。
- 参数说明:
- fd :就是用户程序打开设备时使用open函数返回的文件标示符,
- cmd :就是用户程序对设备的控制命令,
- … : 省略号,那是一些补充参数,即可变参数列表,一般最多一个,有或没有是和cmd的意义相关的。
- 返回值:成功为0,出错为-1
2. ioctl的必要性
如果不用ioctl的话,也可以实现对设备I/O通道的控制,但那是蛮拧了。例如,我们可以在驱动程序中实现write的时候检查一下是否有特殊约定的数据流通过,如果有的话,那么后面就跟着控制命令(一般在socket编程中常常这样做)。但是如果这样做的话,会导致代码分工不明,程序结构混乱,程序员自己也会头昏眼花的。所以,我们就使用ioctl来实现控制的功能。要记住,用户程序所作的只是通过命令码(cmd)告诉驱动程序它想做什么,至于怎么解释这些命令和怎么实现这些命令,这都是驱动程序要做的事情。
3. 案例
从键盘 IO 设备中,读取键盘的数据。
运行结果如下:
版权声明:
本文来源网络,所有图片文章版权属于原作者,如有侵权,联系删除。
本文网址:https://www.mushiming.com/mjsbk/6375.html