网络IO模型

本文介绍了网络IO的两个阶段,等待数据准备和数据拷贝,并探讨了高并发服务器的Reactor和Proactor模型。Reactor是同步I/O事件驱动,通过多路复用器、事件分发器和事件处理器处理并发I/O。而Proactor使用异步I/O,操作由系统完成,提高线程效率。文章还提到了跨平台事件库如libevent、libev和libuv。总结来说,理解Reactor原理对于构建高性能服务器至关重要。
摘要由CSDN通过智能技术生成
  • 网络IO:

        网络IO会涉及到两个系统对象 一个是 用户空间 调用 IO 的进程或者线程,另一个是 内核

        空间的 内核系统, 比如 发生 IO 操作 read 时,它会经历两个阶段
                1. 等待数据准备就绪
                2. 将数据 从内核拷贝到进程 或者线程 中。

  • 服务器模型 Reactor 与 Proactor

          对高并发编程网络连接上的消息处理,可以分为两个阶段:等待消息准备好、消息

        处理。当使用默认的阻塞套接字时(例如上面提到的 1 个线程捆绑处理 1 个连接),往

        往是把这两个阶段合而为一,这样操作套接字的代码所在的线程就得睡眠来等待消息准

        备好,这导致了高并发下线程会频繁的睡眠、唤醒,从而影响了 CPU 的使用效率。高并

        发编程方法当然就是把两个阶段分开处理。即,等待消息准备好的代码段,与处理消息

        的代码段是分离的。当然,这也要求套接字必须是非阻塞的,否则,处理消息的代码段

        很容易导致条件不满足时,所在线程又进入了睡眠等待阶段。那 么问题来了,等待消息

        准备好这个阶段怎么实现?它毕竟还是等待,这意味着线程还是要睡眠的!解决办法

        就是,线程主动查询,或者让 1 个线程为所有连接而等待!这就是 IO 多路复用了。多路

        复用就是处理  等待消息准备好这件事的,但它可以同时处理多个连接!它也可能 等

        待 ””,所以它也会导致线程睡眠,然而这不要紧,因为它一对多、它可以监控所有连接。这样,当我们的线程被唤醒执行时,就一定是有一些连接准备好被我们的代码执行了。作为一个高性能服务器程序通常需要考虑处理三类事件: I/O 事件,定时事件及信号。两种 高效 的事件处理模型: Reactor 和 Proactor。

  • Reactor模型

  

         Reactor 释义 反应堆 ””,是一种事件驱动机制。和普通函数调用的不同之处在于:应用程序不是主动的调用某个 API 完成处理,而是恰恰相反, Reactor 逆置了事件处理流程,应用程序需要提供相应的接口并注册到 Reactor 上,如果相应的时间发生, Reactor 将主动调用应用程序注册的接口,这些接口又称为 回调函数 。

        Reactor 模式是处理并发I/O 比较常见的一种模式,用于同步I/O,中心思想是将所有要处理的I/O 事件注册到一个中心I/O 多路复用器上,同时主线程/进程阻塞在多路复用器上;一旦有I/O 事件到来或是准备就绪(文件描述符或socket 可读、写),

        多路复用器返回并将事先注册的相应I/O 事件分发到对应的处理器中。

        Reactor 模型有三个重要的组件:

  • 多路复用器:由操作系统提供,在linux 上一般是select, poll, epoll 等系统调用。
  • 事件分发器:将多路复用器中返回的就绪事件分到对应的处理函数中。
  • 事件处理器:负责处理特定事件的处理函数。

具体流程如下:

  • 注册读就绪事件和相应的事件处理器;
  • 事件分离器等待事件;
  • 事件到来,激活分离器,分离器调用事件对应的处理器;
  • 事件处理器完成实际的读操作,处理读到的数据,注册新的事件,然后返还控制权;

Reactor 模式是编写高性能网络服务器的必备技术之一,它具有如下的优点:

  • 响应快;
  • 编程相对简单,可以最大程度的避免复杂的多线程及同步问题,并且 避免了多线程进程的切换开销
  • 可扩展性,可以方便的通过增加 Reactor 实例个数来充分利用 CPU 资源;
  • 可复用性, reactor 框架本身与具体事件处理逻辑无关,具有很高的复用性;

实际Reactor 模型可能是这样:

  •  Proactor模型

    • 具体流程如下:
    • 处理器发起异步操作,并关注I/O 完成事件
    • 事件分离器等待操作完成事件
    • 分离器等待过程中,内核并行执行实际的I/O 操作,并将结果数据存入用户自定义缓冲区,最后通知事件分离器读操作完成
    • I/O 完成后,通过事件分离器呼唤处理器
    • 事件处理器处理用户自定义缓冲区中的数据

,  我们可以发现proactor 模型最大的特点就是Proactor 最大的特点是使用异步I/O。所有

        的I/O 操作都交由系统提供的异步I/O 接口去执行。工作线程仅仅负责业务逻辑。在

        Proactor 中,用户函数启动一个异步的文件操作。同时将这个操作注册到多路复用器

        上。多路复用器并不关心文件是否可读或可写而是关心这个异步读操作是否完成。异

        步操作是操作系统完成,用户程序不需要关心。多路复用器等待直到有完成通知到来。

        当操作系统完成了读文件操作——将读到的数据复制到了用户先前提供的缓冲区之后,

        通知多路作系统完成了读文件操作——将读到的数据复制到了用户先前提供的缓冲区

        之后,通知多路复用器相关操作已完成。多路复用器再调用相应的处理程序,处理数据。

    Proactor 增加了编程的复杂度,但给工作线程带来了更高的效率。Proactor 可以在

        系统态将读写优化,利用I/O 并行能力,提供一个高性能单线程模型。在windows 上,

        由于没有epoll 这样的机制,因此提供了IOCP 来支持高并发, 由于操作系统做了较好

        的优化,windows 较常采用Proactor 的模型利用完成端口来实现服务器。在linux 上,

        在2.6 内核出现了aio 接口,但aio 实际效果并不理想,它的出现,主要是解决poll 性能

        不佳的问题,但实际上经过测试,epoll 的性能高于poll+aio,并且aio 不能处理accept,
  因此linux 主要还是以Reactor 模型为主。

  • Libevent libev libuv 

                libevent 

                        名气最大,应用最广泛,历史悠久的跨平台事件库;
                libev :

                        较较libeventlibevent而言,设计更简练,性能更好,但对而言,设计更

                        简练,性能更好,但对WindowsWindows支持不够好;支持不够好;
                libuv :

                        开发开发nodenode的过程中需要一个跨平台的事件库,他们首选了的过程中

                        需要一个跨平台的事件库,他们首选了libevlibev,但又要支持,但又要

                        支持WindowsWindows,故重新封装了一套,,故重新封装了一套,linuxlinux

                        下用下用libevlibev实现,实现,WindowsWindows下用下用IOCPIOCP实现;

  • 总结:

  掌握了Reactor原理,为以后学习其他网络框架底层代码,打下了基础。

  • 技术参考

  C/C++Linux服务器开发/后台架构师【零声教育】-学习视频教程-腾讯课堂

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值