学习笔记-应用编程和网络编程-6(高级IO+附代码)

本文详细介绍了Linux中的IO模型,包括非阻塞IO、阻塞IO、并发式IO(通过非阻塞和多路复用实现)、多路复用IO(select和poll函数)以及异步IO。通过实例代码展示了如何实现键盘和鼠标输入的并发读取,并解释了异步IO的工作原理和使用方法。内容深入浅出,适合理解各种IO模型在系统调用层面的应用。
摘要由CSDN通过智能技术生成

欢迎访问个人GitHub博文
2020.12.19

一、非阻塞IO

1、阻塞式:进程条件没有满足时,进程一直在等待,满足条件才返回,期间也不占用资源。
常见的阻塞:wait pause sleep等
好处:有利于操作系统的性能释放。

2、非阻塞式:
希望提高效率;
实现:O_NONBLOCK(使用open打开文件)和fcntl

二、阻塞式IO

#include <stdio.h>
#include <unistd.h>
#include <string.h>

int main()
{
	//读取键盘
	//键盘就是标准输入,stdin
	char buf[100];

	memset(buf,0,sizeof(buf));
	printf("before read.\n");
	read(0,buf,2);
	printf("读出的内容是:[%s].\n",buf);
	return 0;
}

在这里插入图片描述
程序一直等待键盘输入,阻塞式;

如下图所示,移动鼠标就会有显示,说明这个文件就是鼠标输入文件。
在这里插入图片描述
读鼠标

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


int main()
{
	int fd = -1;
	char buf[200];

	fd = open("/dev/input/by-path/pci-0000:00:04.0-event-mouse",O_RDONLY);
	if (fd < 0)
	{
		perror("open");
		return -1;
	}

	memset(buf,0,sizeof(buf));
	printf("before read.\n");
	read(fd,buf,5);
	printf("读出的内容是:[%s].\n",buf);
	
	return 0;
}

(3)同时读鼠标和键盘
如果使用阻塞式程序,就无法实现鼠标和键盘的任意输入。
解决办法是并发式IO

三、并发式IO

1、非阻塞式IO
(1)实现非阻塞式读取键盘

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

int main()
{
	int flag = -1;
	char buf[100];

	//把0号文件描述符(stdin)变成非阻塞式的
	flag = fcntl(0,F_GETFL);   //先获取原来的galg
	flag |= O_NONBLOCK;         //添加非阻塞属性
	fcntl(0,F_SETFL,flag);      //更新flag
	//这三步之后,0就变成了非阻塞式

	memset(buf,0,sizeof(buf));
	printf("before read.\n");
	read(0,buf,5);
	printf("读出的内容是:[%s].\n",buf);
	
	return 0;
}

在这里插入图片描述
(2)读鼠标
使用open更加简单,只需要添加O_NONBLOCK属性

	fd = open("/dev/input/by-path/pci-0000:00:04.0-event-mouse",O_RDONLY);

但这样的方式实现同时读取效率不高。

2、多路复用IO

3、异步通知(异步IO)

四、多路复用IO

1、IO multiplexing

为了解决多路非阻塞式io的问题,因为非阻塞式IO 是以一种轮询的方式实现,CPU需要反复的去查看。
因此使用多路复用IO,涉及到的函数有select和poll
实现原理:外部阻塞式(select和poll是阻塞式),内部非阻塞式自动轮询多路阻塞式

2、select函数

man 2 select

3、poll函数

man 2 poll
两个函数功能是一样的。

4、实战

2021.1.6
(1)select实现

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

int main()
{
	int fd = -1;
	int ret =-1;
	char buf[200];
	fd_set myset;
	struct timeval tm;

	//读鼠标
	fd = open("/dev/input/by-path/pci-0000:00:04.0-event-mouse",O_RDONLY);
	if (fd < 0)
	{
		perror("open");
		return -1;
	}
	//当前有两个fd,一个是fd一个是0(标准输入)
	//使用之前处理myset
	FD_ZERO(&myset);
	FD_SET(fd,&myset);
	FD_SET(0,&myset);

	tm.tv_sec = 5;//秒
	tm.tv_usec = 0;//微秒

	ret = select(fd +1,&myset,NULL,NULL,&tm);//阻塞
	if (ret < 0)
	{
		perror("select: ");
		return -1;
	}
	else if (ret == 0)
	{
		printf("超时了\n");
	}
	else
	{
		//等到了一路IO,然后检测是哪一个IO
		if(FD_ISSET(0,&myset))
		{
			//这里处理键盘
			memset(buf,0,sizeof(buf));
			read(0,buf,5);
			printf("键盘读出的内容是:[%s].\n",buf);
		}

		if (FD_ISSET(fd,&myset))
		{
			//这里处理鼠标
			memset(buf,0,sizeof(buf));
			read(fd,buf,5);
			printf("鼠标读出的内容是:[%s].\n",buf);
		}
		
	}
		
	return 0;
}

在这里插入图片描述
(2)poll实现

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


int main()
{
	int fd = -1,ret =-1;
	char buf[200];
	struct pollfd myfds[2] = {0};

	//读鼠标
	fd = open("/dev/input/by-path/pci-0000:00:04.0-event-mouse",O_RDONLY);
	if (fd < 0)
	{
		perror("open");
		return -1;
	}

	//初始化定义的数组
	myfds[0].fd = 0;  //键盘
	myfds[0].events = POLLIN;  //等待读操作

	myfds[1].fd = fd;  //鼠标
	myfds[1].events = POLLIN;  //等待读操作

	ret = poll( myfds ,fd +1,10000);//10000ms
	if (ret < 0)
	{
		perror("poll: ");
		return -1;
	}
	else if (ret == 0)
	{
		printf("超时了\n");
	}
	else
	{
		//等到了一路IO,然后检测是哪一个IO
		if(myfds[0].events == myfds[0].revents)
		{
			//这里处理键盘
			memset(buf,0,sizeof(buf));
			read(0,buf,5);
			printf("键盘读出的内容是:[%s].\n",buf);
		}

		if (myfds[1].events == myfds[1].revents)
		{
			//这里处理鼠标
			memset(buf,0,sizeof(buf));
			read(fd,buf,5);
			printf("鼠标读出的内容是:[%s].\n",buf);
		}
		
	}
		
	return 0;
}

在这里插入图片描述

五、异步IO

可以认为:异步IO就是操作系统用软件实现的一套中断响应系统。
工作方法:
(1)当前进程注册一个异步IO事件(使用signal注册一个信号SIGIO的处理函数)
(2)当异步事件发生后,系统停止正常的进程,转而去执行绑定的函数处理这个异步事件。
涉及到的函数:
(1)fcntl(F_GETFL、F_SETFL、O_ASYNC、F_SETOWN)
(2)signal或者sigaction(SIGIO)
实践:

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

int fd = -1;

//绑定SIGIO信号,函数处理异步通知事件
void func(int sig)
{
	char buf[200] = {0};

	if (sig != SIGIO)
	{
		return;
	}

	read(fd,buf,5);
	printf("鼠标读出的内容是:[%s].\n",buf);
	
}

int main()
{
	int fd = -1,ret =-1,flag = -1;
	char buf[200] = {0};

	//读鼠标
	fd = open("/dev/input/by-path/pci-0000:00:04.0-event-mouse",O_RDONLY);
	if (fd < 0)
	{
		perror("open");
		return -1;
	}

	//	注册异步通知(把鼠标的文件描述符设置为可以接受异步IO)
	flag = fcntl(fd, F_GETFL);
	flag |=	O_ASYNC;
	fcntl(fd, F_SETFL,flag);
	//把异步IO事件的接收进程设置为当前进程
	fcntl(fd, F_SETOWN,getpid());

	//注册当前进程的SIGIO信号捕获函数
	signal(SIGIO,func);

	
	//读键盘
	while (1)
	{
		memset(buf,0,sizeof(buf));
		read(0,buf,5);
		printf("键盘读出的内容是:[%s].\n",buf);
	}
		
	return 0;
}

在这里插入图片描述

六、存储映射IO

(1)mmap函数
例如LCD显示和IPC之间共享内存。
(2)特点
1、共享不是复制,减少内存操作;
2、处理大文件时效率高。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值