目录
fcntl函数
#include <unistd.h> #include <fcntl.h> int fcntl(int fd, int cmd); int fcntl(int fd, int cmd, long arg); int fcntl(int fd, int cmd, struct flock *lock);
- 返回: 若成功则依赖于cmd,若出错为-1
- 功能: 可以改变已经打开文件的性质
- 常见的功能
- 复制一个现存的描述符, 新文件描述符作为函数值返(cmd=F_DUPFD)
- 获得/设置文件描述符标志(cmd= F_GETFD或F_SETFD)
- 获得/设置文件状态标志(cmd = F_GETFL或F_SETFL)
- 获得/设置文件锁(cmd = F_SETLK、cmd = F_GETLK、 F_SETLKW)
- 第三个参数为struct flock结构体
- cmd的常见取值
F_DUPFD
- 复制文件描述符,新的文件描述符作为函数返回值返回。
F_GETFD/F_SETFD
- 获取/设置文件描述符,通过第三个参数设置。
F_GETFL/F_SETFL
- 获取/设置文件状态标志,通过第三个参数设置。
- 可以更改的几个标志是:O_APPEND, O_NONBLOCK, SYNC, O_ASYNC(O_RDONLY、O_WRONLY和O_RDWR不适用)
- include文件夹下io.h
#ifndef _IO_H_ #define _IO_H_ extern void copy(int fdin, int fdout); extern void set_fl(int fd, int flag); extern void clr_fl(int fd, int flag); #endif
- src文件夹下io.c实现
void set_fl(int fd,int flag){ //获得原来的文件状态标志 int val=fcntl(fd, F_GETFL); //增加新的文件状态标志 val |=flag; //重新设置文件状态标志(val为新的文件状态标志) if(fcntl(fd, F_SETFL, val)<0){ perror("fcntl error"); }
void clr_fl(int fd,int flag){ int val=fcntl(fd,F_GETFL); //清除指定的文件状态标志(置为0) val &= ~flag; if(fcntl(fd, F_SETFL, val) < 0){ perror("fcntl error"); } }
- 调用
int fd = open(argv[2], O_WRONLY); //设置追加的文件状态标志 set_fl(fd, O_APPEND); /* int fd=open(argv[2],O_WRONLY | O_APPEND); if(fd<0){ perror("open error"); exit(1); } */
#define BUFFER_LEN 1024 void set_fl(int fd, int flag){ int val = fcntl(fd, F_GETFL); val |= flag; if(fcntl(fd, F_SETFL, val) < 0){ fprintf(stderr, "fcntl error: %s\n", strerror(errno)); } } void clr_fl(int fd, int flag){ int val = fcntl(fd, F_GETFL); val &= ~flag; if(fcntl(fd, F_SETFL, val) < 0){ fprintf(stderr, "fcntl error: %s\n", strerror(errno)); } }
ioctl函数
#include <unistd.h> #include <sys/ioctl.h> int ioctl(int fd, int request, ...);
- 返回: 若成功则为其它值,出错返回-1
- I/O操作的杂物箱
- 不能用一般的函数表示的I/O操作通常都能用ioctl表示。
- 终端I/O是ioctl的最大使用方面,主要用于设备的I/O控制。
int fd = -1; char name[256] = "Unknown"; if((fd = open("/dev/input/event1",O_RDONLY)) < 0){ perror("open error"); exit(1); } if(ioctl(fd,EVIOCGNAME(sizeof(name)),name) < 0){ perror("evdev ioctl error"); } printf("The device says its name is %s\n", name); close(fd);
I/O处理方式
- I/O处理的五种模型
阻塞I/O模型
- 若所调用的I/O函数没有完成相关的功能就会使进程挂起,直到相关数据到达才会返回。如:终端、网络设备的访问。
非阻塞模型
- 当请求的I/O操作不能完成时,则不让进程休眠,而且返回一个错误。如:open、read、write访问。
I/O多路转换模型
- 如果请求的I/O 操作阻塞,且他不是真正阻塞I/O,而且让其中的一个函数等待,在这期间, I/O还能进行其他操作。如:select函数。
信号驱动I/O模型
- 在这种模型下,通过安装一个信号处理程序,系统可以自动捕获特定信号的到来,从而启动I/O。
异步I/O模型
- 在这种模型下,当一个描述符已准备好,可以启动I/O时,进程会通知内核。由内核进行后续处理,这种用法现在较少。
- 非阻塞I/O
- 低速系统调用时,进程可能会阻塞
- 非阻塞I/O确定操作(read,open,write)不阻塞,如果操作不能完成,则出错返回。
- 设定非阻塞的方式
- 使用open打开文件,设置O_NONBLOCK标志。
- 如果一个文件已经打开,则使用fcntl修改文件状态标志。
- 阻塞案例
char buffer[4096] = {'\0'}; ssizetsize=0; sleep(5); size = read(STDIN_FILENO, buffer, sizeof (buffer)); if(size < 0){ perror("read error") ; exit(1) ; }else if(size == 0){ printf("read finished!\n"); }else{ if(write(STDOUT_FILENO, buffer, size) != size){ perror("write error") ; exit (1) ; } }
- 阻塞,5秒钟后继续等待输入
- 非阻塞案例
char buffer[4096] = {'\0'}; ssizetsize=0; //设置非阻塞I0 set_fl(STDIN_FILENO,O_NONBLOCK); sleep(5); size = read(STDIN_FILENO, buffer, sizeof (buffer)); if(size < 0){ perror("read error") ; exit(1) ; }else if(size == 0){ printf("read finished!\n"); }else{ if(write(STDOUT_FILENO, buffer, size) != size){ perror("write error") ; exit (1) ; } }
- 非阻塞,5秒钟后直接退出并返回错误
Linux程序设计:fcntl函数、ioctl函数、I/O处理方式
最新推荐文章于 2021-10-09 16:59:36 发布