IO模型和IO复用

五中网络IO模型

IO的执行分为等待数据和拷贝数据两个阶段。

阻塞IO

指IO操作彻底完成后才返回用户空间。IO执行的数据等待和数据拷贝两个阶段都被阻塞。几乎所有的IO接口都是阻塞型的。改进方案:使用多线程、多进程、线程池、连接池。

非阻塞IO

指IO操作被调用后立即返回给用户一个状态值,不需要等到IO操作彻底完成才返回。在数据准备阶段,用户进程不被阻塞,但是需要不断轮询,询问内核数据是否准备好。

复用IO

是指使用select、poll、epoll等函数调用来同时监控多个套接字描述符的操作。可以等待多个套接字中的任何一个变为可读,就可以通知用户执行数据拷贝。这一函数调用过程是被阻塞的,当某一个套接字可读时返回,之后再使用recvfrom把数据从内核复制到进程空间。
他可以让单个进程具有处理多个IO事件的能力,又被称为事件驱动IO(Event Driven IO)。

异步IO

应用进程执行aio_read系统调用之后会立即返回,应用进程可以继续执行,不会被阻塞,内核在所有操作完成之后向应用进程发送信号。

信号驱动IO

应用进程使用sigaction 系统调用,内核立即返回,应用进程可以继续执行,也就是说数据准备阶段应用进程是非阻塞的。当数据准备好之后,内核向应用进程发送SIGIO信号,进程收到信号之后再调用recvfrom将数据从内核复制到应用进程中。
相比于非阻塞IO,信号驱动IO的CPU利用率更高。
相比于异步IO,信号驱动IO通知应用进程可以开始IO,而异步IO是通知应用进程IO完成。
在这里插入图片描述

IO复用函数调用

select、poll、epoll都是IO复用的具体实现,他们三者出现的时间顺序一次向后。

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

有三种类型的描述符类型:readset、writeset、exceptset,分别对应读、写、异常条件的描述符集合。fd_set使用数组实现,数组大小使用FD_SETSIZE定义,
timeout为超时参数,调用select会一直阻塞直到有描述符的时间到达或者超时。成功调用返回值大于0,出错返回结果为-1,超时返回0。

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

pollfd使用链表实现。
select和poll的比较,二者基本相同,但实现细节有所不同:
-功能
- select会修改描述符,但poll不会;
- select的描述符类型使用数组实现,FD_SETSIZE默认1024,因此只能监听1024个描述符。如果需要监听更多,需要修改FD_SETSIZE后重新编译;而poll描述符类型使用链表实现,没有数量限制。
- poll提供更多的时间类型,并且对描述符服用利用率更高。
- 如果一个线程对某描述符调用了select或者poll,但另一线程关闭了该描述符,会导致结果不确定。

  • 速度
    • 都比较慢,需要将全部描述符从应用进程缓冲区复制到内核缓冲区。
    • 返回结果中没有申明哪些描述符准备好,如果返回值大于零,应用进程需要轮询扎到IO完成的描述符。
  • 可移植性
    • 几乎所有系统支持select,但比较新的系统才支持poll。
epoll
int epoll_create(int size);
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);

epoll_ctl() 用于向内核注册新的描述符或者是改变某个文件描述符的状态。已注册的描述符在内核中会被维护在一棵
红黑树上,通过回调函数内核会将 I/O 准备好的描述符加入到一个链表中管理,进程调用 epoll_wait() 便可以得到事
件完成的描述符。
从上面的描述可以看出,epoll 只需要将描述符从进程缓冲区向内核缓冲区拷贝一次,并且进程不需要通过轮询来获
得事件完成的描述符。

epoll只适用于Linux OS。
epoll比select和poll更加灵活,没有进程描述符数量的限制。
epoll对多线程更友好,一个线程调用epoll_wait() 另一个线程关闭了同一个描述符也不会产生像 select 和
poll 的不确定情况。

epoll的工作模式

LT模式

当epoll_wait函数检测到描述符时间到达,将此事件通知给进程,进程可以不立即处理该事件,下次调用epoll_wait 会再次通知该进程,这是默认的一种工作模式。

ET模式

和LT模式不同的是,通知进程后必须立即处理事件,下次调用epoll_wait函数将不会再得到事件到达的通知。这种模式减少了epoll事件触发的次数,因此效率要高。只支持No-blocking,避免由于一个文件句柄的阻塞读、写操作把处理多个文件描述符的任务饿死。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值