【linux应用编程高级IO基础使用】

linux应用编程高级IO基础使用

`


前言

今天分享的是linux应用编程下的高级IO的一些使用,主要会从阻塞IO/非阻塞IO/多路复用IO(select、poll) /异步IO等进行相应的事例demo演示。
下面每种情况的dmeo都是基于鼠标键盘的读取操作
基础文件描述符
0 ->input (标准输入)
1->output (标准输出)
2->error(标准错误)

下面对每个知识点的讲解可能不会很清楚,自己也是才接触,分享的都是一些简单的认识和一些小练习demo,大家可以去看这位博主的。
linux 高级IO

一、阻塞式IO

阻塞IO形象的来讲就是,当你去车站买票 然后你的前面有很多人,你一直在哪里等前面的人走了后你才可以购买到,而你一直等待那段时间就是阻塞,什么都做不了。放到我们进程中来讲就是,当一个进程在等待莫一事件发生然后在执行相应的程序,如果这个触发事件没有发生,这个进程就会被阻塞,函数不能被立即返回,而被阻塞的进程是不占用cpu资源的。

下面结构图来自其他博主,可以去看这位博主的

在这里插入图片描述

//查看鼠标相关设备
ls /dev/input  可能大家的鼠标设备名称会不同我的是mouse0

cat /dev/input/mouse0 查看是否正确
//移动鼠标会有信息打印,则说明当前这个设备名称就是我们的鼠标设备

在这里插入图片描述

/*==================read mouse=============*/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>


//阻塞式IO
int main(void)
{
	//读取鼠标
	int fd = -1;
	char buf[128];
	fd = open("/dev/input/mouse0",O_RDONLY);
	if(fd < 0)
	{
		printf("perror:\n");
		return -1;
	}
	memset(buf,0,sizeof(buf));
	printf("read before\n");
	read(fd,buf,sizeof(buf));
	printf("read text:[%s] \n",buf);
	return 0;
}
/*================read keyboard===========*/
#include <stdio.h>
#include <string.h>
#include <unistd.h>

//阻塞式IO

int main(void)
{
	//读取键盘
	
	//键盘就是标准输入,stdin
	//ssize_t read(int fd, void *buf, size_t count);
	char buf[128];
	memset(buf,0,sizeof(buf));
	printf("read before\n");
	read(0,buf,sizeof(buf));
	printf("read text:[%s] \n",buf);
	return 0;
}

二、非阻塞式IO

非阻塞式IO还是以买票形象的来讲就是,我们每隔一段时间就去看看还没有人,而其他的时间我们可以做其他的事情不会被影响。每次进程查看的时候都会有一个返回结果,效率比起阻塞式IO高很多。

在这里插入图片描述

进行先关函数API调用的时候我们通过man手册进行使用查看
man 2 open
/*=================read mouse==============*/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>


int main(void)
{
	//读取鼠标
	int fd = -1;
	char buf[128];
	fd = open("/dev/input/mouse0",O_RDONLY | O_NONBLOCK); //一只读非组撒式打开
	if(fd < 0)
	{
		printf("perror:\n");
		return -1;
	}
	memset(buf,0,sizeof(buf));
	printf("read before\n");
	read(fd,buf,sizeof(buf));
	printf("read text:[%s] \n",buf);
	return 0;
}

在这里插入图片描述

/*=================read keyboard=============*/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>

int main(void)
{
	//读取键盘
	//键盘就是标准输入,stdin
	//ssize_t read(int fd, void *buf, size_t count);
	char buf[128];
	int flag = -1;
	memset(buf,0,sizeof(buf));
	
	// int fcntl(int fd, int cmd, ... /* arg */ );
	//把0号文件描述符(stdin)变成非阻塞式的
	flag = fcntl(0,F_GETFL); //先获取原来的flag
	flag |= O_NONBLOCK; //添加阻塞属性
	fcntl(0,F_SETFL,flag); //更新flag
	//这三步之后0 就变成了非阻塞的
	
	printf("read before\n");
	read(0,buf,sizeof(buf));
	printf("read text:[%s] \n",buf);
	return 0;
}

三、并发式IO解决

并发这个词很形象从上面的demo来讲的话,就是鼠标和键盘我们可以同时进行。还是先进行阻塞式的demo然后进行非阻塞式并发IO

阻塞式读键盘和鼠标

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>

//阻塞式IO
int main(void)
{
	//读取鼠标
	int fd = -1;
	char buf[128];
	fd = open("/dev/input/mouse0",O_RDONLY);
	if(fd < 0)
	{
		printf("perror:\n");
		return -1;
	}
	memset(buf,0,sizeof(buf));
	printf("read mouse before\n");
	read(fd,buf,sizeof(buf));
	printf("read text:[%s] \n",buf);
	
	//读取键盘
	memset(buf,0,sizeof(buf));
	printf("read before\n");
	read(0,buf,sizeof(buf));
	printf("read text:[%s] \n",buf);
	return 0;
}

非阻塞式读键盘鼠标

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>

int main(void)
{
	
	int fd = -1;
	int flag = -1;
	int ret = -1;
	char buf[128];
	//把0号文件描述符(stdin)变成非阻塞式的
	flag = fcntl(0,F_GETFL); //先获取原来的flag
	flag |= O_NONBLOCK; //添加阻塞属性
	fcntl(0,F_SETFL,flag); //更新flag
	fd = open("/dev/input/mouse0",O_RDONLY | O_NONBLOCK);
	if(fd < 0)
	{
		printf("perror:\n");
		return -1;
	}
	while(1)
	{
		//读取鼠标
		memset(buf,0,sizeof(buf));
		//printf("read mouse before\n");
		ret = read(fd,buf,sizeof(buf));
		if(ret > 0)
		{
		printf("read text:[%s] \n",buf);
		}
		
		//读取键盘
		
		memset(buf,0,sizeof(buf));
		//printf("read keyboard before\n");
		ret = read(0,buf,sizeof(buf));
		if(ret > 0)
		{
		printf("read text:[%s] \n",buf);
		}
	}
	return 0;
}

四、IO多路复用

主要是select、poll、epoll;对一个IO端口,两次调用,两次返回,比阻塞IO并没有什么优越性;关键是能实现同时对多个IO端口进行监听。下面会以select 和poll进行演示

select io 多路复用
首先我们先进行相关函数API使用查看
在这里插入图片描述

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/select.h>
#include <sys/time.h>

int main(void)
{
	int fd = -1;
	int ret = -1;
	char buf[128];
	fd_set myset;
	struct timeval tm;
	fd = open("/dev/input/mouse0",O_RDONLY | O_NONBLOCK);
	if(fd < 0)
	{
		perror("open:");
	}
	
	// int select(int nfds, fd_set *readfds, fd_set *writefds,
    //             fd_set *exceptfds, struct timeval *timeout);
	//当前有两个Fd 一个是0一个是fd
	FD_ZERO(&myset);  //先清零
	FD_SET(fd,&myset); //将Fd添加到myset
	FD_SET(0,&myset);  //将0添加到Myset 
	
	tm.tv_sec  = 10;
	tm.tv_usec = 0;
	
	ret = select(fd + 1,&myset,NULL,NULL,&tm);
	if(ret < 0)
	{
		perror("select\n");
	}
	else if(ret == 0)
	{
		printf("over time\n");
	}
	else
	{
		//等到了一路IO ,然后去监听到底是哪个IO到了进行处理
		if(FD_ISSET(0,&myset))
		{
			//这里处理键盘
			memset(buf,0,sizeof(buf));  //先将缓存清空
			read(0,buf,sizeof(buf));    //读取数据
			printf("read keyboard:[%s].\n",buf);
		}
		if(FD_ISSET(fd,&myset))
		{
			//这里处理鼠标
			memset(buf,0,sizeof(buf));  //先将缓存清空
			read(0,buf,sizeof(buf));    //读取数据
			printf("read mouse:[%s].\n",buf);
		}
	}
	return 0;
}

poll 多路IO复用

在这里插入图片描述

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <poll.h>


int main(void)
{
	int fd = -1;
	int ret = -1;
	char buf[128];
	struct pollfd myfds[2]= {0};
	fd = open("/dev/input/mouse0",O_RDONLY | O_NONBLOCK);
	if(fd < 0)
	{
		perror("open:");
	}
	
	//int poll(struct pollfd *fds, nfds_t nfds, int timeout);

	//当前有两个Fd 一个是0一个是fd
	//初始化myfds
	myfds[0].fd = 0 ;          //键盘输入文件符
	myfds[0].events = POLLIN;  //等待读操作
	
	myfds[1].fd = fd;          //鼠标输入文件符
	myfds[1].events = POLLIN;  //等待读操作
	
	ret = poll(myfds,fd + 1,10000);
	if(ret < 0)
	{
		perror("poll\n");
		return -1;
	}
	else if(ret == 0)
	{
		printf("over time\n");
	}
	else
	{
		//等到了一路IO ,然后去监听到底是哪个IO到了进行处理
		if(myfds[0].events == myfds[0].revents)
		{
			//这里处理键盘
			memset(buf,0,sizeof(buf));  //先将缓存清空
			read(0,buf,sizeof(buf));    //读取数据
			printf("read keyboard:[%s].\n",buf);
		}
		if(myfds[1].events == myfds[1].revents)
		{
			//这里处理鼠标
			memset(buf,0,sizeof(buf));  //先将缓存清空
			read(fd,buf,sizeof(buf));    //读取数据
			printf("read mouse:[%s].\n",buf);
		}
	}
	return 0;
}

五、异步IO

异步IO就是操作系统用软件实现的一套中断响应系统
异步IO的工作方法是:我们当前进程注册一个异步IO事件(使用signal注册一个信号SIGIO的处理函数),然后当前进程可以正常处理自己的事情,当异步事件发生后当前进程会收到一个SIGIO信号从而执行绑定的处理函数去处理这个异步事件。

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>

int mousefd = -1;
char buf[128];

//绑定SIGIO 信号,在函数内处理异步通知事件
void func(int sig)
{
	if(sig != SIGIO)
	{
		return;
	}
	memset(buf,0,sizeof(buf));  //先将缓存清空
	read(mousefd,buf,sizeof(buf));    //读取数据
	//printf("read mouse:[%s].\n",buf);
}


int main(void)
{
	int flag = -1;
	mousefd = open("/dev/input/mouse0",O_RDONLY | O_NONBLOCK);
	if(mousefd < 0)
	{
		perror("open:");
	}
	// int fcntl(int fd, int cmd, ... /* arg */ );
	//把鼠标的文件描述符设置为可以接受异步IO
	flag = fcntl(mousefd,F_GETFL);
	flag |= O_ASYNC;
	fcntl(mousefd,F_SETFL,flag);
	
	//把异步IO事件的接收事件设置为当前进程
	fcntl(mousefd,F_SETOWN,getpid());
	
	//注册当前进程的SIGIO信号的捕获函数
	signal(SIGIO,func);
	while(1)
	{
		memset(buf,0,sizeof(buf));  //先将缓存清空
		read(0,buf,sizeof(buf));    //读取数据
		printf("read keyboard:[%s].\n",buf);
	}
	return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小殷学长

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值