Linux高性能服务器编程

ch05 Linux网络编程基础API

  • socket 地址API

    字节序,现代CPU的累加器一次都能装载(至少)4字节(考虑32位机,下同),即一个整数。4字节在内存中排列的顺序将影响它被累加器装在成的整数值。

    大端字节序(网络字节序):一个整数的高位字节(23-31bit)存储在内存的低地址初,低位字节(0-7bit)存储在内存的高地址处

    小端字节序(主机字节序) 则指 整数的高位字节存储在内存的高地址处,低位字节存储在内存的低地址处。

    • 主机字节序 ,现代PC大多采用小端字节序
    • 网络字节序,它给所有接收数据的主机提供了一个正确解释收到的格式化数据的保证
  • socket 基础API

  • 网络信息API

ch08 高性能服务器程序框架

  • 服务器模型

    • C / S 模型

      客户连接请求是随机到达的异步事件,服务器需要使用某种I / O模型来监听这一事件。 下图种,服务器使用的 I / O复用技术之一的 select系统调用

      image-20220227152644693

      • C / S模型非常适合资源相对集中的场合,并且实现简单,但缺点明显:服务器是通信的中心,当访问量过大时,可能所有客户都将得到很慢的响应。
    • P2P模型。下图a所示的模型存在一个显著的问题,即主机之间很难互相发现。 所以实际上使用P2P模型通常带有一个专门的发现服务器(通常还提供查找服务(甚至提供内容服务),使每个客户能尽快找到自己需要的资源)。

      image-20220227153320116

      从编程角度,P2P模型可以看作C/S模型的扩展。

  • 服务器编程框架

    image-20220227153420368

    image-20220227153446888

    image-20220227153503876

  • I / O模型

    image-20220227153931699

  • 两种高效的事件处理模式

    • 服务器程序通常需要处理三类事件:I / O事件、信号及定时事件。

    • 同步I/O模型通常用于实现Reactor模式,异步I/O模型则用于实现Proactor模式。

    • Reactor模式 (它要求主线程(I/O处理单元)只负责监听文件描述上是否有事件发生,有的话立即将该事件通知工作线程(逻辑单元)。除此之外 主线程不做任何其他实质性的工作。

      • 使用同步I / O模型(以epoll_wait为例)实现的Reactor模式的工作流程:

        1. 主线程往epoll内核事件中注册socket上的读就绪事件;
        2. 主线程调用 epoll_wait等待socket上有数据可读
        3. 当socket上有数据可读时,epoll_wait通知主线程。主线程则将socket可读事件放入请求队列
        4. 睡眠在请求队列上的某个工作线程被唤醒,它从socket读取数据,并处理客户请求,然后往epoll内核事件表中注册该socket上的写就绪事件;
        5. 主线程调用epoll_wait等待socket可写;
        6. 当socket可写时,epoll_wait通知主线程。主线程将socket可写事件放入请求队列;
        7. 睡眠在请求队列上的某个工作线程被唤醒,它往socket上写入服务器处理客户请求的结果。

        image-20220227155052296

    • Proactor模式 (与Reactor模式不通,它将所有I/O操作都交给主线程和内核来处理,工作线程仅仅负责业务逻辑。

      • 使用异步 I / O模型(以aio_read 和 aio_write为例)实现的Proactor模式的工作流程:

        image-20220227155333515

  • 两种高效的并发模式 (并发模式:I/O处理单元和多个逻辑单元之间协调完成任务的方法。

    • 服务器 主要有两种并发编程模式: 半同步 / 半异步 模式; 领导者/追随者模式。

    • 半同步 / 半异步模式 (既要求较好的实时性、又能同时处理多个客户请求的应用程序。同步线程处理 客户逻辑,异步线程处理 I/O事件

      • 在I/O模型中,“同步”和"异步" 区分的是 内核向应用程序通知的是何种I/O事件(是就绪事件还是完成事件),以及该由谁来完成I/O读写(是应用程序还是内核)。 在并发模式中,“同步”指的是 程序完全按照代码序列的顺序执行,“异步”指的是程序的执行需要由系统事件来驱动。 常见的系统事件包括:中断、信号等。

      • 并发模式中的同步和异步 image-20220227155942562

      • 同步线程(按同步方式运行的线程)

        • 效率相对较低,实时性差, 但逻辑简单
      • 异步线程(按异步方式运行)

        • 效率高,实时性强, 但编写代码相对复杂,难以调试和扩展,而且不适合于大量的并发。
      • 半同步 / 半异步模式的工作流程

        image-20220227160515610

      • 半同步 / 半异步模式的一种变体 —— 半同步 / 半反应堆模式

        image-20220227160633279

        上图(8-10)中,主线程插入请求队列中的任务是就绪的连接socket,说明该图采用的事件处理模式是Reactor模式:要求工作线程自己从socket上读取客户请求和往socket写入服务器应答。 这就是 该模式名称中的“half-reactive”的含义。

        • 半同步 / 半反应堆模式的 缺点:
          • 主线程和工作线程共享请求队列。主线程往请求队列中添加任务,或者工作线程从请求队列中取出任务,都需要对请求队列加锁保护,从而白白耗费CPU时间
          • 每个工作线程在同一时间只能处理一个客户请求。如果客户数量较多,而工作线程较少,则请求队列中将堆积很多任务对象,客户端的响应速度将越来越慢。如果通过增加工作线程来解决这一问题,则工作线程的切换也将消大量CPU时间。
      • 高效的 半同步 / 半反应堆模式 (每个工作线程都能同时处理多个客户连接)

        image-20220227161326757

        • 每个线程(主线程、工作线程)都维持自己的事件循环,他们各自独立地监听不同的事件。 因此,在这种高效的半同步/半异步模式中,每个线程都工作在异步模式,所以 它并非严格意义上的半同步/半异步模式。
    • 领导者 / 追随者模式

      image-20220227161628627

  • 有限状态机

ch09 I/O 复用

网络程序在下列情况需要使用I/O复用技术:

  • 客户端程序要同时处理多个socket; 如 非阻塞connet技术;
  • 客户端程序要同时处理用户输入和网络廉价而。如 本章讨论的聊天室程序;
  • TCP服务器要同时处理监听socket和连接socket。 I/O复用使用最多的场合
  • 服务器要同时处理TCP请求和UDP请求。比如 本章讨论的回射服务器
  • 服务器要同时监听多个端口,或处理多种服务。 如 本章讨论的xinetd服务器。
  • select 系统调用 (用途:在一段指定时间内,监听用户感兴趣的文件描述符上的可读、可写和异常等事件。)

    • select 原型

      1
      2
      3
      
      #include <sys/select.h>
      int select(int nfds, fd_set* readfds, fd_set* writefds, fd_set* exceptfds, struct timeval* timeout);
      // nfds 指定被监听的文件描述符的总数。
      
    • fd_set结构体定义:image-20220228131229608

  • poll系统调用

  • epoll系列系统调用

  • 三组I / O 复用函数的比较

  • I/O复用的高级应用一:非阻塞connect

  • I/O复用的高级应用二:聊天室程序

  • I/O复用的高级应用三:同时处理TCP和UDP程序

  • 超级服务xinetd