Linux程序设计:fcntl函数、ioctl函数、I/O处理方式

目录

fcntl函数

ioctl函数

I/O处理方式


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秒钟后直接退出并返回错误

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值