主要介绍网络IO五大模型。
1 网络IO介绍
网络IO:阻塞IO(BIO),非阻塞(NIO),多路复用,异步,信号驱动等
网络IO的两个阶段流程:
1 网络数据被拷贝到内核缓冲区
2 内核缓冲区数据被拷贝到用户缓冲区
当用户一次网络读写请求的时候服务器的流程如下:
2 阻塞IO
阶段1,阶段2都阻塞就网络io是阻塞IO。当用户发起读写请求,内核空间数据未满时候,就等待数据;当内核数据满了后,将内核数据拷贝到用户空间,直到用户空间数据满的时候,才解锁用户进程的阻塞状态。
对于从网卡到内核缓冲区和内核缓冲区到用户进程缓冲区都是阻塞的。
缺点:需要配置多线程处理。常见的 阻塞IO+多线程一个连接对应一个线程。程序开辟线程的数量有限,线程开销较大。所以处理客户端数量有限。面对百万连接无法处理。
3 非阻塞IO
应用程序网络读写请求时,如果内核缓冲区数据未满时,立即返回给用户程序时,而非阻塞IO需要一直不停的询问内核缓冲区是否准备好了;如果准备好了进入第二个阶段,阻塞在内核缓冲区数据拷贝到用户缓冲区,拷贝完成后返回给应用程序。
非阻塞IO需要内核支持,在创建连接的时候,可条用setsockop函数设置noblocking
优点:解决阻塞IO每个连接一个线程处理的问题,一个线程可以处理多个连接。
缺点:用户多次发起系统调用。频繁调用浪费资源。
4 IO多路复用
复用:通过有限此系统调用来实现管理多个网络连接。 如目前10个连接,可以通过一次系统调用select/poll将10个连接都丢给内核,让内核告知那些socket的数据就绪了,然后去读取这些连接上的Data。
4.1 select/poll
select,poll最大的fd连接数,系统默认1024,在linux配置文件中可以修改。但是也是有限的。
优点:降低系统调用次数,较少的线程来处理网络连接。
缺点:用户需要将海量的sockted集合从用户态传递到内核态,让内核态检测网络连接是否ok,开销较大。数据的拷贝降低了IO的速度。
4.2 epoll
解决poll,select需要拷贝的问题,epoll直接在内核开辟一段区域(共享空间)。内核2.6版本才引入。
还有另外一个机制事件驱动机制:不再主动遍历所有的文件描述符,而是通过事件驱动的方式主动通知内核该文件描述符的数据准备完毕了,然后内核就将其写入链表中即可
epoll三个基本函数:
epoll_create:内核动态分配一段区域 底层红黑树+链表
epoll_ctl:增删改红黑树的结点
epoll_wait:用来在1阶段阻塞,等待就绪fd。
分类:
LT 水平触发
ET 边沿触发 仅仅支持no_block socket。
优点:一开始就在内核分配一段共享空间用来管理fd,不必频繁的从用户态拷贝管理fd到内核结婚。
缺点:引入了红黑树和链表 空间暂用大,个人猜想后面内核版本会如何降低占用空间发展。
5 异步IO
应用进程通过 aio_read 告知内核启动某个操作,并且在整个操作完成之后再通知应用进程,包括把数据从内核空间拷贝到用户空间。异步 IO 模型是由内核通知我们 IO 操作何时完成。是真正意义上的无阻塞的IO操作,但是目前只有windows支持AIO,linux内核暂时不支持。
内核态拷贝数据到用户态这种方式也是交给系统线程来实现,不由用户线程完成
6 信号驱动
在IO执行的数据准备阶段,不会阻塞用户进程。当用户进程需要等待数据的时候,会向内核发送一个信号,告诉内核需要数据,然后用户进程就继续做别的事情去了,而当内核中的数据准备好之后,内核立马发给用户进程一个信号,用户进程收到信号之后,立马调用recvfrom,去查收数据。该IO模型使用的较少。
主要是通过信号函数,在应用程序处理,和异步IO还有点区别
7 总结
前四种模型的主要区别于第一阶段,因为他们的第二阶段都是一样的:在数据从内核拷贝到应用进程的缓冲区期间,进程都会阻塞。相反,异步 IO 模型在这两个阶段都不会阻塞,从而不同于其他四种模型。
阻塞/非阻塞IO:区别主要是在网络io的第一阶段来区别定义
同步/异步IO:当网络io的第一,二阶段都非阻塞时候才是异步。
linux也有异步aio机制,为何linux一直用同步呢,为何异步不常用?
经过4个版本迭代,还是发现性能还是不如epoll同步,但是异步aio机制用在磁盘读写