【Linux-15】高级IO

低谷时刻,
你需要一颗强心针,让你迅速回血,拥抱每天清晨的太阳吧!

目录: 

1、五种IO模型

2、多路转接IO

3、IO多路转接

  • select模型
  • poll模型
  • epoll模型

>>五种IO模型

五种典型的模型:阻塞/非阻塞/信号驱动/异步/多路转接IO

 这几种IO的发展过程:效率以及对资源的利用率越来越高,但是占用的资源越来越多,并且流程控制越来越复杂

阻塞:为了完成某个功能,发起系统调用,当前若不具备完成条件,则等待条件具备,完成功能后返回

非阻塞:为了完成某个功能,发起系统调用,当前若不具备完成条件,则立即报错返回

阻塞和非阻塞和区别:发起调用后,调用是否立即返回。

同步:为了完成某个功能,发起系统调用,当前不具备成条件,则进程等待,等待功能完成。

异步:为了完成某个功能,发起系统调用,功能有其他进程完成。

同步阻塞:

异步非阻塞:

>>多路转接IO

对大量IO事件是否就绪的阻塞监控并告诉用户当前哪一个IO是就绪的;

事件是否就绪:当前的描述符是否可读/可写/异常

优点:进程可以针对就绪的描述符进行操作,(避免没有就绪的描述符进行无用操作);tcp服务器同一时间只能于一个客户端通信一次,对没有就绪的描述符进行操作之后或导致程序阻塞;

socket可读事件就绪:socket接受缓冲区中的数据大小大于低水位标记(通常默认为1个字节)

socket可写事件就绪:socket发送缓冲区中的剩余空间大小大于低水位标记

>>IO多路转接

IO多路转接模型:实现多路转接IO功能的方法

1、select模型:

#include <sys/select.h>

int select(int nfds,   fd_set *readfds,   fd_set *writefds,  fd_set *exceptfds,   struct timeval *timeout);

nfds:            maxfd + 1---最大文件描述符+1,避免空遍历判断,提高性能       

readfds/writefds/exceptfds:可读/可写/异常事件集合

timeout:struct timeval{...}    做一个阻塞监控,一个超时返回   NULL:永久阻塞   0:立即返回

返回值:>0 就绪的描述符个数   ==0 等待超时   <0 监控出错;

   void FD_CLR(int fd, fd_set *set);     // 用来清除描述词组set中相关fd 的位
   int FD_ISSET(int fd, fd_set *set);   // 用来测试描述词组set中相关fd 的位是否为真
   void FD_SET(int fd, fd_set *set);     // 用来设置描述词组set中相关fd的位
   void FD_ZERO(fd_set *set);             // 用来清除描述词组set的全部位
select优缺点:
	1、select所监控的描述符数量有最大上限----1024(_FD_SETSIZE)
	2、select每次需要将描述符集合拷贝到内核进行监控(内核态和用户态之间的数据拷贝)
	3、select在内核中对所有的描述符进行轮询遍历判断是否就绪(性能随着描述符增多而下降)、
	4、select就绪后会移除集合中非就绪的描述符,修改集合;每次监控需要重新添加描述符(编码复杂)
	5、select返回给用户就绪的描EPOLL_CTL_MOD述符集合,但还不会直接告诉用户哪些描述符处于就绪状态(需要用户进行轮询遍历一遍判断哪些描述符在集合中,进而找出就绪的描述符对其操作)(性能随着描述符增多而下降) 
	
优点:
	1、select遵循posix,可以跨平台
	2、select监控超时等待时间,可以精确到微秒

2、poll模型 :

#include <poll.h>

int poll(struct pollfd *fds, nfds_t nfds, int timeout);

功能:对大量描述符进行事件监控

int fd:    用户所要监控的描述符

uint32_t events:    用户对监控的描述符所关心的事件 POLLIN |POLLOUT

uint32_t revents:    描述符实际就绪事件


    1、用户为每一个关心的描述符定义事件结构(文件描述符/用户所关心的事件)
    2、将描述符事件结构体数组拷贝到内核中进行监控
    3、轮询遍历事件数组中的描述符,判断描述符是否就绪了某个事件
        若没有描述符就绪用户关心的事件,则每隔一会遍历判断一次
        若有描述符就绪用户关心的事件,则会将就绪的事件放到事件结构体的revents中,并调用返回
    4、调用返回

poll优缺点:
	1、poll每次监控都需要将所有的事件结构信息拷贝到内核
	2、在内核poll进行就绪判断同样使用轮询遍历判断(性能随着描述符增多而下降)
	3、描述符就绪后,poll修改描述符事件结构中的revents信息为当前就绪的事件;但是不会直接告诉用户哪些描述符处于就绪状态
	(需要用户进行轮询遍历一遍判断哪些描述符在集合中,进而找出就绪的描述符对其操作)(poll相较于select实际上对大量描述符进行监控的原理并没有发上改变,性能并没有多大提高)
	4、poll不能跨平台

优点:
	1、poll采用事件结构的方式对描述符进行监控,简化了多个描述符集合的监控编码流程
	2、poll没有描述符数量的上限限制(取决于硬件资源)

 3、epoll模型:<Linux下最优秀的多路转接模型>

#include <sys/epoll.h>

int epoll_create(int size);------>在内核中创建eventpoll结构,并且返回文件描述符作为操作句柄

struct epoll_event{

        uint32_t event;   //用户对于描述符所要监控的事件

        union epoll_data_t data(int fd,void* ptr)     //  fd :用户所要监控的描述符,ptr:所要发生就绪的事件    
    }

int epoll_ctl(int epfd,  int op,  int fd,  struct epoll_event *event);

epfd: 创建epoll中的epoll的描述符

op-->三种操作-->EPOLL_CTL_ADD / EPOLL_CTL_MOD / EPOLL_CTL_DEL  添加/修改/移除一个内核中的监控节点

fd:用户所要监控的描述符

返回值:>0 就绪的描述符个数      ==0 等待超时      <0 监控出错

epoll监控原理:

通过epoll_create创建eventpoll结构,返回操作句柄;

通过操作句柄向内核中添加描述符的监控事件epoll_ctl;

epoll开始监控之后,告诉操作系统开始替进程监控内核指定的eventpoll结构体中的红黑树中的所有事件节点;

操作系统为每一个描述符定义了一个事件回调(当描述符指定事件就绪的时候,则将这个描述符对应的事件结构信息节点添加到eventpoll结构体中的双向链表中);

epoll的事件触发方式有两种:

水平触发(event=EPOLLLT)--->默认的触发方式

边缘触发(event=EPOLLET)

水平触发只要缓冲区中有数据,就会发生触发事件,进而对描述符进行读取数据;

边缘触发每一条数据只触发一次,处理过程就需要用户将所有的数据读取完毕,因为事件不会被触发第二次,等待下一条数据到来的时候才会触发下一次事件;

解决方案:

将IO操作设置为非阻塞:recv(fd,buf,MSG_DONTWAIT)

将描述符设置为非阻塞:fcntl(fd,F_SETFL,flag | O_NONBLOCK)  设置描述符属性为增加一个非阻塞属性

 

!!!这里的以及上面的优缺点是需要重点记住的地方

epoll优缺点:
	1、监控的描述符数量无最大上限
	2、采用事件结构对描述符进行监控,简化了多个描述符集合的监控编码流程
	3、epoll的事件信息,每条信息只需要向内核拷贝一次
	4、epoll是一个异步阻塞操作,操作系统对描述符事件进行监控-----采用回调的方式,不需要精心轮询遍历描述符进行判断(性能不会随着描述符增多而下降)
	5、当描述符就绪后将描述信息添加到双向链表中,epoll_wait只需要每隔一会看一下链表是否为空,就可以判断出是否有描述符事件就绪
	6、当epoll_wait返回时,直接将就绪的事件信息拷贝到用户给与的事件结构数组中;相当于直接告诉了用户那些描述符是就绪的,用户可以直接对描述符进行操作(避免遍历非就绪描述符,遍历的都是就绪事件)
	
优点:
	1、epoll不能跨平台
	2、监控超时等待时间只能精确到毫秒

 多路转接模型的使用场景:多路转接模型实现高并发相较于多线程/多进程消耗资源更少,但是并非适用所有的场景!!它适用于有大量描述符需要监控,但是同一时间只有少量活跃,并每个描述符的处理时间不能太长的情况下。

 

 

 

 

 

 

~bye~

 


 

 

 

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值