zoukankan      html  css  js  c++  java
  • 网络IO模型

    IO有两种操作,同步IO和异步IO。同步IO指的是,必须等待IO操作完成后,控制权才返回给用户进程。异步IO指的是,无须等待IO操作完成,就将控制权返回给用户进程。

    网络中的IO,由于不同的IO设备有着不同的特点,网络通信中往往需要等待。常见的有以下4种情况。

    (1)输入操作:等待数据到达套接字接收缓冲区。

    (2)输出操作:等待套接字发送缓冲区有足够的空间容纳将要发送的数据。

    (3)服务器接收连接请求:等待新的客户端连接请求的到来。

    (4)客户端发送连接请求:等待服务器会送你个客户的发起的SYN所对应的ACK。

    当一个网络IO(假设是read)发生时,它会涉及两个系统对象,一个是调用这个IO的进程,另一个是系统内核。当一个read操作发生时,它会经历两个阶段:(1)等待数据准备;(2)将数据从内核拷贝到进程中。

    4种网络IO模型

    (1)阻塞IO模型(2)非阻塞IO模型(3)多路IO复用模型(4)异步IO模型

    1.阻塞IO模型

    在Linux中,默认情况下所有的socket都是阻塞的,一个典型的读写流程如下图:

    阻塞和非阻塞的概念描述的是用户线程调用内核IO操作的方式:阻塞是指IO操作需要彻底完成后才返回用户空间;而非阻塞是指IO操作被调用后立即返回给用户一个状态值,不需要等到IO操作彻底完成。

     2.非阻塞IO模型

    在Linux下,可以通过设置socket使IO变为非阻塞状态。当对一个非阻塞的socket执行read操作时,流程如下图

    3.多路IO复用模型

    多路IO复用,有时也称为事件驱动IO。它的基本原理就是有个函数(如select)会不断地轮询所负责的socket,当某个socket有数据到达了,就通知用户进程,多路IO复用模型的流程图如下:

    select、poll和epoll的区别

    select、poll和epoll都是多路IO复用的机制。多路IO复用就通过一种机制,可以监视多个描述符,一旦某个描述符就绪(一般是读就绪或者写就绪),能够通知程序进行相应的读写操作。但select、poll和epoll本质上都是同步IO,因为它们都需要在读写事件就绪后自己负责进行读写,即是阻塞的,而异步IO则无须自己负责进行读写,异步I/O的实现会负责把数据从内核拷贝到用户空间。

    下面对这3种多路IO复用进行对比。

    (1) 首先还是来看常见的select()和poll()。对于网络编程来说,一般认为poll比select要高级一些,这主要源于以下几个原因。

    1)poll()不要求开发者在计算最大文件描述符时进行+1的操作。

    2)poll()在应付大数目的文件描述符的时候速度更快,因为对select()来说内核需要检查大量描述符对应的fd_set中的每一个比特位,比较费时。

    3)select()可以监控的文件描述符数目是固定的,相对来说也较少(1024或2048)。如果需要监控数值比较大的文件描述符,或是分布得很稀疏的较少的描述符,效率也会很低。而对于poll()函数来说,就可以创建特定大小的数组来保存监控的描述符,而不受文件描述符值大小的影响,而且poll()可以监控的文件数目远大于select()。

    4)对于select()来说,所监控的fd_set在select返回之后会发生变化,所以在下一次进入select()之前都需要重新初始化需要监控的fd_set,poll()函数将监控的输入和输出事件分开,允许被监控的文件数组被复用而不需要重新初始化。

    5)select()函数的超时参数在返回时也是未定义的,考虑到可移植性,每次在超时之后在下一次进入到select()之前都需要重新设置超时参数。

    (2)select()的优点如下所述。

    1)select的可移植性更好,在某些UNIX系统上不支持poll().

    2)select()对于超时值提供了更好的精度,而poll()是精度较差。

    (3)epoll的优点如下所述。

    1)支持一个进程打开大数目的socket描述符(FD)

    select()最不能忍受的是一个进程所打开的FD是有一定限制的,由FD_SETSIZE的默认值是1024/2048。对于那些需要支持上万连接数目的IM服务器来说显然太少了。这时候可以选择修改这个宏然后重新编译内核。不过epoll则没有这个限制,它所支持的FD上限是最大可以打开文件的数目,这个数字一般大于2048.举个例子,在1GB内存的空间中这个数字一般是10万左右,具体数目可以使用cat/proc/sys/fs/file-max查看,一般来说这个数目和系统内存关系很大。

    2)IO效率不随FD数目增加而线性下降。

    传统的select/poll另一个致命弱点就是当你拥有一个很大的socket集合,不过由于网络延迟,任一时间只有部分的socket是“活跃”的,但是selecct/poll每次调用都会线性扫描全部的集合,导致效率呈现线性下降。但是epoll不存在这个问题,它只会对“活跃”的socket进行操作——这是因为在内核中实现epoll是根据每个fd上面的callback函数实现的。那么,只有“活跃”的socket才会主动去调用callback函数,其他idle状态socket则不会,在这个点上,epoll实现了一个“伪”AIO,因为这时候推动力由Linux内核提供。

    3)使用mmap加速内核与用户空间的消息传递

    这点实际上涉及epoll的具体实现。无论是selecct、poll还是epoll都需要内核把fd消息通知给用户空间,如何避免不必要的内存拷贝就显得尤为重要。在这点上,epoll是通过内核与用户空间mmap处于同一块内存实现的。

    对于poll来说需要将用户传入的pollfd数组拷贝到内核空间,因为拷贝操作和数组长度相关,时间上来看,这是一个O(n)操作,当事情发生后,poll将获得的数据传送到用户空间,并执行释放内存和剥离等待队列等工作,向用户空间拷贝数据与剥离等待队列等操作的时间复杂度同样是O(n)。

  • 相关阅读:
    用word2007发布带图片博客windows服务程序
    ActiveRecord与GridView,ObjectDataSource配合使用时的问题
    Spring.NET & NHibernate文章收集
    myOleDbConnection.GetOleDbSchemaTable异常
    想看本书《CSS禅意花园》
    一个考生表,现在要随机生成考号,遇到sql疑问,请教各位大虾
    选中与复制表格
    ActiveRecord多表查询
    DotNetNuke与MemberShip的结合(五年版)
    IIS+php5.0+mysql架设
  • 原文地址:https://www.cnblogs.com/wuyepeng/p/10167751.html
Copyright © 2011-2022 走看看