🕺🏻 周末程序猿 🗓️ 2025-06-10 🗂️ 博客剪藏 🏷️ #网络编程 #C++

C++ 高并发服务器模型实现

声明

本项目实现了多种不同的后端服务器并发模型,展示了各种网络编程和并发处理技术。所有实现都使用 C++11 标准,不依赖第三方库。

项目结构

concurrency_server/
├── base/                           # 基础组件目录
│   └── server_base.h              # 服务器基类,提供通用的socket操作
├── benchmark/                      # 性能测试工具目录
├── main.cpp                        # 主程序入口,支持多种服务器模型切换
├── Makefile                        # 编译配置文件
├── README.md                       # 项目说明文档
│
├── 基础并发模型
├── single_process_server.h         # 单进程模型 - 串行处理,适合学习
├── multi_thread_server.h           # 多线程模型 - 每连接一线程
├── multi_process_server.h          # 多进程模型 - 每连接一进程
├── thread_pool_server.h            # 线程池模型 - 固定数量工作线程
├── process_pool1_server.h          # 进程池模型1 - 预创建进程池
├── process_pool2_server.h          # 进程池模型2 - 改进的进程池实现
│
├── I/O多路复用模型
├── select_server.h                 # Select模型 - 跨平台I/O多路复用
├── poll_server.h                   # Poll模型 - 改进的select实现
├── epoll_server.h                  # Epoll模型 - Linux高性能I/O复用
├── kqueue_server.h                 # Kqueue模型 - BSD/macOS高性能I/O复用
│
├── 高级并发架构
├── reactor_server.h                # Reactor模式 - 事件驱动架构
├── proactor_server.h               # Proactor模式 - 异步I/O架构
├── event_loop_server.h             # 事件循环模型 - 单线程事件驱动
├── half_sync_async_server.h        # 半同步半异步模式 - 分层处理
├── leader_follower_server.h        # Leader-Follower模式 - 动态角色切换
├── producer_consumer_server.h      # 生产者消费者模式 - 解耦处理
├── pipeline_server.h               # 管道模式 - 流水线处理
├── work_stealing_server.h          # 工作窃取模式 - 负载均衡
├── hybrid_server.h                 # 混合模式 - 多种技术结合
│
├── 现代并发技术
├── coroutine_server.h              # 协程模型 - 用户态轻量级线程
├── fiber_server.h                  # 纤程模型 - 协作式多任务
├── actor_server.h                  # Actor模型 - 消息传递并发

支持的并发模型

1. SingleProcess (单进程模型)

详细介绍: 单进程模型是最简单的服务器架构,采用传统的阻塞I/O方式处理客户端请求。
服务器在单个进程中运行,使用一个主循环来依次处理每个客户端连接。
当有新连接到达时,服务器调用accept()接受连接,然后同步读取客户端数据、处理请求并发送响应。整个过程是串行的,一次只能处理一个客户端。

实现架构

sequenceDiagram
    participant C1 as Client1
    participant C2 as Client2
    participant S as Server Process
    
    C1->>S: Connect
    S->>S: Accept & Process Request
    S->>C1: Response
    Note over S: 串行处理,一次只能处理一个请求
    C2->>S: Connect (等待)
    S->>S: Accept & Process Request
    S->>C2: Response

2. MultiProcess (多进程模型)

详细介绍: 多进程模型通过为每个客户端连接创建独立的子进程来实现并发处理。
主进程负责监听新连接,当accept()接受到新客户端时,立即调用fork()创建子进程来处理该连接,而主进程继续监听下一个连接。
每个子进程拥有独立的内存空间和资源,可以并行处理不同的客户端请求。
这种模型提供了最强的隔离性,一个进程的崩溃不会影响其他进程或主服务器。

实现架构

flowchart TD
    A[Main Process] --> B[Listen Socket]
    B --> C{New Connection?}
    C -->|Yes| D[fork]
    D --> E[Child Process 1]
    D --> F[Child Process 2]
    D --> G[Child Process N]
    E --> H[Handle Client 1]
    F --> I[Handle Client 2]
    G --> J[Handle Client N]
    C -->|No| C
    
    style E fill:#e1f5fe
    style F fill:#e1f5fe
    style G fill:#e1f5fe

3. MultiThread (多线程模型)

详细介绍: 多线程模型通过为每个客户端连接创建独立线程来实现并发处理。
主线程负责监听和接受新连接,当有新客户端连接时,创建一个工作线程来处理该连接的所有I/O操作。
所有线程共享同一个进程的内存空间,可以方便地共享数据和资源。
相比多进程模型,线程的创建和切换开销更小,内存使用更高效。但需要特别注意线程安全问题,避免竞态条件和数据竞争。

实现架构

flowchart TD
    A[Main Thread] --> B[Listen Socket]
    B --> C{New Connection?}
    C -->|Yes| D[Create Thread]
    D --> E[Worker Thread 1]
    D --> F[Worker Thread 2]
    D --> G[Worker Thread N]
    E --> H[Handle Client 1]
    F --> I[Handle Client 2]
    G --> J[Handle Client N]
    C -->|No| C
    
    K[Shared Memory Space]
    E -.-> K
    F -.-> K
    G -.-> K
    
    style E fill:#fff3e0
    style F fill:#fff3e0
    style G fill:#fff3e0

4. ProcessPool1 (进程池模型1)

flowchart TD
    A[Master Process] --> B[Create Process Pool]
    B --> C[Worker Process 1]
    B --> D[Worker Process 2]
    B --> E[Worker Process N]
    
    F[Shared Listen Socket] --> G{accept}
    C --> G
    D --> G
    E --> G
    
    G -->|Process 1 wins| H[Handle Client 1]
    G -->|Process 2 wins| I[Handle Client 2]
    G -->|Process N wins| J[Handle Client N]
    
    style C fill:#e8f5e8
    style D fill:#e8f5e8
    style E fill:#e8f5e8
    style F fill:#ffecb3

5. ProcessPool2 (进程池模型2 - SO_REUSEPORT)

flowchart TD
    A[Master Process] --> B[Create Process Pool]
    B --> C[Worker Process 1]
    B --> D[Worker Process 2]
    B --> E[Worker Process N]
    
    F[Port 8080] --> G[SO_REUSEPORT]
    C --> H[Listen Socket 1]
    D --> I[Listen Socket 2]
    E --> J[Listen Socket N]
    
    G --> H
    G --> I
    G --> J
    
    K[Kernel Load Balancer] --> H
    K --> I
    K --> J
    
    style C fill:#e8f5e8
    style D fill:#e8f5e8
    style E fill:#e8f5e8
    style K fill:#f3e5f5

6. ThreadPool (线程池模型)

详细介绍: 线程池模型通过预先创建固定数量的工作线程来处理客户端请求,避免了为每个连接动态创建线程的开销。
主线程负责接受新连接并将连接放入任务队列,工作线程从队列中取出任务进行处理。
这种模型有效控制了系统资源使用,避免了线程数量无限增长导致的系统崩溃。
线程池的大小通常根据CPU核心数和预期负载来设定,实现了更好的资源管理和性能优化。

实现架构

flowchart TD
    A[Main Thread] --> B[Create Thread Pool]
    B --> C[Worker Thread 1]
    B --> D[Worker Thread 2]
    B --> E[Worker Thread N]
    
    A --> F[Accept Connections]
    F --> G[Task Queue]
    
    C --> H{Get Task}
    D --> I{Get Task}
    E --> J{Get Task}
    
    G --> H
    G --> I
    G --> J
    
    H --> K[Process Client]
    I --> L[Process Client]
    J --> M[Process Client]
    
    style C fill:#fff3e0
    style D fill:#fff3e0
    style E fill:#fff3e0
    style G fill:#e3f2fd

7. LeaderAndFollower (领导者/跟随者模型)

详细介绍: 领导者/跟随者模型是一种高性能的并发模式,通过动态角色切换来优化线程利用率。
在任何时刻,只有一个线程担任领导者角色,负责监听和接受新的连接或事件,其他线程处于跟随者状态等待被激活。
当领导者接收到事件后,它会将自己降级为跟随者去处理该事件,同时从跟随者中选举出新的领导者继续监听。
这种模型避免了传统模型中的线程池调度开销,减少了线程间的竞争,提高了CPU缓存的局部性。特别适合高并发、低延迟的网络服务场景。

实现架构

stateDiagram-v2
    [*] --> Leader: Thread becomes leader
    Leader --> Processing: Accept connection
    Processing --> Follower: Promote next follower
    Follower --> Leader: Wait for promotion
    Processing --> [*]: Complete request
    
    state Leader {
        [*] --> Listening
        Listening --> AcceptConnection: New connection
        AcceptConnection --> [*]
    }
    
    state Processing {
        [*] --> HandleRequest
        HandleRequest --> SendResponse
        SendResponse --> [*]
    }

8. Select (Select I/O多路复用)

详细介绍: Select模型是最经典的I/O多路复用技术,通过select()系统调用在单线程中同时监控多个socket的状态变化。
服务器维护读、写、异常三个文件描述符集合,select()会阻塞等待直到至少一个描述符就绪。
当select()返回时,服务器遍历描述符集合,处理所有就绪的I/O操作。
这种模型避免了多线程的复杂性,用单线程就能处理多个并发连接,是事件驱动编程的基础。

实现架构

flowchart TD
    A[Main Loop] --> B[fd_set readfds]
    B --> C[Add listen_fd]
    B --> D[Add client_fd1]
    B --> E[Add client_fd2]
    B --> F[Add client_fdN]
    
    G[select] --> H{Ready FDs?}
    C --> G
    D --> G
    E --> G
    F --> G
    
    H -->|listen_fd ready| I[Accept new connection]
    H -->|client_fd ready| J[Read/Write data]
    H -->|timeout| K[Continue loop]
    
    I --> A
    J --> A
    K --> A
    
    style B fill:#e1f5fe
    style G fill:#fff3e0

9. Poll (Poll I/O多路复用)

详细介绍: Poll模型是select模型的改进版本,使用poll()系统调用来监控多个文件描述符的I/O事件。
与select不同,poll使用pollfd结构数组来描述要监控的文件描述符和事件类型,没有FD_SETSIZE的限制,可以监控任意数量的描述符。
poll()返回时,通过检查每个pollfd结构的revents字段来确定哪些描述符就绪。这种模型保持了select的单线程优势,同时解决了描述符数量限制问题。

实现架构

flowchart TD
    A[Main Loop] --> B[pollfd array]
    B --> C["pollfd[0]: listen_fd"]
    B --> D["pollfd[1]: client_fd1"]
    B --> E["pollfd[2]: client_fd2"]
    B --> F["pollfd[N]: client_fdN"]
    
    G[poll] --> H{Check revents}
    C --> G
    D --> G
    E --> G
    F --> G
    
    H -->|POLLIN on listen_fd| I[Accept new connection]
    H -->|POLLIN on client_fd| J[Read data]
    H -->|POLLOUT on client_fd| K[Write data]
    H -->|POLLHUP/POLLERR| L[Close connection]
    
    I --> M[Add to pollfd array]
    J --> A
    K --> A
    L --> N[Remove from array]
    M --> A
    N --> A
    
    style B fill:#e8f5e8
    style G fill:#fff3e0

10. Epoll (Epoll I/O多路复用)

详细介绍: Epoll是Linux内核提供的高性能I/O多路复用机制,专门为解决C10K问题而设计。
与select/poll不同,epoll使用事件驱动的方式,只返回就绪的文件描述符,避免了线性扫描。
Epoll内部使用红黑树管理文件描述符,使用就绪列表存储活跃事件,实现了O(1)的事件通知效率。 支持水平触发(LT)和边缘触发(ET)两种模式,为高性能服务器提供了极大的灵活性。

实现架构

flowchart TD
    A[epoll_create] --> B[epoll_fd]
    B --> C[epoll_ctl ADD listen_fd]
    
    D[Main Loop] --> E[epoll_wait]
    E --> F{Ready Events?}
    
    F -->|listen_fd EPOLLIN| G[Accept connection]
    F -->|client_fd EPOLLIN| H[Read data]
    F -->|client_fd EPOLLOUT| I[Write data]
    F -->|client_fd EPOLLHUP| J[Close connection]
    
    G --> K[epoll_ctl ADD client_fd]
    H --> L[Process request]
    I --> M[Send response]
    J --> N[epoll_ctl DEL client_fd]
    
    K --> D
    L --> D
    M --> D
    N --> D
    
    style B fill:#ffecb3
    style E fill:#e8f5e8
    style F fill:#f3e5f5

11. Kqueue (Kqueue I/O多路复用)

详细介绍: Kqueue是FreeBSD和macOS系统提供的高性能事件通知机制,类似于Linux的epoll但功能更强大。
Kqueue不仅支持网络I/O事件,还支持文件系统变化、信号、定时器等多种事件类型。通过kevent()系统调用统一管理所有事件,提供了一致的编程接口。
Kqueue使用内核事件队列,只通知发生变化的事件,避免了轮询开销。
其设计哲学是提供统一的事件处理框架,让应用程序能够高效地响应各种系统事件。

实现架构

flowchart TD
    A[kqueue] --> B[kqueue_fd]
    B --> C["EV_SET(listen_fd, EVFILT_READ)"]
    C --> D[kevent register]
    
    E[Main Loop] --> F[kevent wait]
    F --> G{Ready Events?}
    
    G -->|listen_fd READ| H[Accept connection]
    G -->|client_fd read| I[Read data]
    G -->|client_fd write| J[Write data]
    G -->|EOF/Error| K[Close connection]
    
    H --> L["EV_SET(client_fd, EVFILT_READ)"]
    I --> M[Process request]
    J --> N[Send response]
    K --> O[Remove from kqueue]
    
    L --> P[kevent add]
    M --> E
    N --> E
    O --> E
    P --> E
    
    style B fill:#ffecb3
    style F fill:#e8f5e8
    style G fill:#f3e5f5

12. Reactor (Reactor模式)

详细介绍: Reactor模式是一种事件驱动的设计模式,将事件检测和事件处理分离,提供了高度可扩展的架构。
该模式定义了一个事件循环,负责监听各种I/O事件,当事件发生时分发给相应的事件处理器。
Reactor模式的核心思想是"不要调用我们,我们会调用你",应用程序注册事件处理器,由Reactor负责在适当时机调用。
这种模式广泛应用于网络编程框架,如Java NIO、Node.js等,提供了优雅的异步编程模型。

实现架构

flowchart TD
    A[Reactor] --> B[Event Demultiplexer]
    B --> C[select/poll/epoll]
    
    D[Event Handlers] --> E[AcceptHandler]
    D --> F[ReadHandler]
    D --> G[WriteHandler]
    
    H[Main Loop] --> I[Handle Events]
    I --> J{Event Type?}
    
    J -->|Accept Event| K[AcceptHandler.handle]
    J -->|Read Event| L[ReadHandler.handle]
    J -->|Write Event| M[WriteHandler.handle]
    
    K --> N[Create new connection]
    L --> O[Read and process data]
    M --> P[Send response]
    
    N --> Q[Register with Reactor]
    O --> R[Update event interest]
    P --> S[Update event interest]
    
    Q --> H
    R --> H
    S --> H
    
    style A fill:#e3f2fd
    style D fill:#fff3e0
    style I fill:#e8f5e8

13. Coroutine (协程模式)

详细介绍: 协程模式通过状态机模拟协程行为,在C++11环境下实现异步编程。与传统的回调方式不同,协程允许函数在执行过程中暂停并在稍后恢复,使异步代码看起来像同步代码。
本实现使用状态机来跟踪每个连接的处理状态,当遇到会阻塞的I/O操作时,协程会yield让出控制权,等待I/O就绪后再resume继续执行。
这种模型特别适合处理大量并发连接,因为协程的内存开销远小于线程,可以创建成千上万个协程而不会耗尽系统资源。

实现架构

stateDiagram-v2
    [*] --> INIT: Create Coroutine
    INIT --> READING: Start read operation
    READING --> PROCESSING: Data available
    READING --> READING: Would block (yield)
    PROCESSING --> WRITING: Process complete
    WRITING --> WRITING: Would block (yield)
    WRITING --> DONE: Write complete
    DONE --> [*]: Coroutine finished
    
    state READING {
        [*] --> CheckSocket
        CheckSocket --> ReadData: Socket ready
        CheckSocket --> Yield: Would block
        ReadData --> [*]: Data read
        Yield --> [*]: Resume later
    }
    
    state WRITING {
        [*] --> CheckSocket
        CheckSocket --> WriteData: Socket ready
        CheckSocket --> Yield: Would block
        WriteData --> [*]: Data written
        Yield --> [*]: Resume later
    }

14. Actor模型

详细介绍: Actor模型是一种基于消息传递的并发计算模型,每个Actor都是独立的计算单元,拥有自己的状态和行为。
Actor之间不共享内存,只能通过异步消息进行通信。
当Actor接收到消息时,可以执行三种操作:处理消息并更新内部状态、向其他Actor发送消息、创建新的Actor。
这种模型天然避免了传统并发编程中的锁和竞态条件问题,提供了更安全的并发处理方式。
Actor模型特别适合构建分布式系统,因为Actor可以分布在不同的机器上,通过网络进行消息传递。

实现架构

flowchart TD
    A[Actor 1] -->|Message| B[Actor 2]
    A -->|Message| C[Actor 3]
    B -->|Message| A
    C -->|Message| A
    D[Actor System] --> A
    D --> B
    D --> C
    
    E[Message Queue 1] --> A
    F[Message Queue 2] --> B
    G[Message Queue 3] --> C
    
    style A fill:#e1f5fe
    style B fill:#e8f5e8
    style C fill:#fff3e0
    style D fill:#f3e5f5

15. 事件循环模型 (Event Loop)

详细介绍: 事件循环模型是一种单线程异步编程模式,通过一个无限循环来处理所有的I/O事件和回调函数。
事件循环不断地检查事件队列,当有事件就绪时执行相应的回调函数。
这种模型的核心思想是将所有阻塞操作转换为非阻塞的异步操作,通过事件通知机制来处理I/O完成。
事件循环模型广泛应用于Node.js、Redis等高性能服务器中,特别适合I/O密集型应用。
由于采用单线程设计,避免了多线程编程中的锁和同步问题,大大简化了编程复杂度。

实现架构

flowchart TD
    A[Event Loop] --> B[Event Queue]
    B --> C[Event Handler]
    C --> D[Callback]
    D --> A
    
    E[I/O Events] --> B
    F[Timer Events] --> B
    G[Network Events] --> B
    
    style A fill:#ffecb3
    style B fill:#e3f2fd
    style C fill:#fff3e0

16. 纤程/用户态线程 (Fiber/Green Thread)

详细介绍: 纤程(Fiber)是一种用户态的轻量级线程,也称为绿色线程或协作式线程。
与操作系统线程不同,纤程的创建、销毁和调度都在用户空间完成,不需要内核参与。
纤程之间采用协作式调度,只有当纤程主动让出控制权时才会发生切换,这避免了抢占式调度的开销和复杂性。
每个纤程只需要很少的内存(通常几KB的栈空间),因此可以创建数十万个纤程而不会耗尽系统资源。
纤程特别适合I/O密集型应用,当遇到阻塞操作时可以快速切换到其他纤程继续执行。

实现架构

flowchart TD
    A[User Thread 1] --> B[Scheduler]
    C[User Thread 2] --> B
    D[User Thread N] --> B
    B --> E[Kernel Thread]
    
    F[Stack 1] --> A
    G[Stack 2] --> C
    H[Stack N] --> D
    
    style A fill:#e8f5e8
    style C fill:#e8f5e8
    style D fill:#e8f5e8
    style B fill:#f3e5f5

17. 工作窃取模型 (Work Stealing)

详细介绍: 工作窃取模型是一种动态负载均衡的并行计算模式,每个工作线程维护自己的任务队列,当线程完成自己队列中的任务后,会尝试从其他线程的队列中"窃取"任务来执行。
这种模型能够自动适应任务执行时间的不均匀性,避免某些线程空闲而其他线程过载的情况。
工作窃取算法最初由Cilk项目提出,后来被广泛应用于Java的ForkJoinPool、Intel TBB等并行计算框架中。
该模型特别适合处理递归分治算法和任务执行时间差异较大的场景。

实现架构

flowchart TD
    A[Thread 1] --> B[Task Queue 1]
    C[Thread 2] --> D[Task Queue 2]
    E[Thread N] --> F[Task Queue N]
    
    A -->|Steal| D
    C -->|Steal| F
    E -->|Steal| B
    
    G[Global Task Pool] --> B
    G --> D
    G --> F
    
    style B fill:#e3f2fd
    style D fill:#e3f2fd
    style F fill:#e3f2fd
    style G fill:#ffecb3

18. 生产者-消费者模型

详细介绍: 生产者-消费者模型是一种经典的并发设计模式,通过缓冲区将数据的生产和消费过程解耦。
生产者负责生成数据并放入缓冲区,消费者从缓冲区取出数据进行处理。
这种模型特别适合处理生产和消费速度不匹配的场景,缓冲区起到了削峰填谷的作用。
在网络服务器中,可以将接收连接作为生产过程,处理请求作为消费过程,通过任务队列进行解耦。
这种模型提高了系统的吞吐量和响应性,同时简化了系统设计。

实现架构

flowchart TD
    A[Producer Thread] --> B[Blocking Queue]
    C[Consumer Thread 1] --> B
    D[Consumer Thread 2] --> B
    E[Consumer Thread N] --> B
    
    F[Client Connections] --> A
    B --> G[Request Processing]
    
    style A fill:#e8f5e8
    style B fill:#ffecb3
    style C fill:#fff3e0
    style D fill:#fff3e0
    style E fill:#fff3e0

19. 半同步/半异步模型 (Half-Sync/Half-Async)

详细介绍: 半同步/半异步模型是一种混合架构模式,将系统分为同步处理层和异步处理层,结合两种模式的优势。
异步层负责高效的I/O处理,使用事件驱动的方式处理网络事件;同步层负责业务逻辑处理,使用传统的同步编程模型。
两层之间通过队列进行通信,异步层将接收到的请求放入队列,同步层的工作线程从队列中取出请求进行处理。
这种模型既保证了I/O处理的高效性,又保持了业务逻辑的简洁性,是实际项目中常用的架构模式。

实现架构

flowchart TD
    A[Client] --> B[Synchronous Layer]
    B --> C[Queue]
    C --> D[Asynchronous Layer]
    D --> E[I/O Operations]
    E --> D
    D --> C
    C --> B
    B --> A
    
    style B fill:#e1f5fe
    style C fill:#ffecb3
    style D fill:#e8f5e8

20. Proactor模式

详细介绍: Proactor模式是一种基于异步I/O的设计模式,与Reactor模式相对应。
在Reactor模式中,应用程序在I/O就绪时被通知并自己执行I/O操作,而在Proactor模式中,应用程序发起异步I/O操作,操作系统完成I/O后通知应用程序处理结果。
这种模式真正实现了I/O操作的异步化,应用程序无需阻塞等待I/O完成,可以继续处理其他任务。
Proactor模式特别适合I/O密集型应用,能够充分利用系统资源,提供更高的并发性能。

实现架构

flowchart TD
    A[Initiator] --> B[Asynchronous Operation]
    B --> C[OS Kernel]
    C --> D[Completion Handler]
    D --> A
    
    E[Application] --> A
    F[I/O Completion Port] --> D
    
    style A fill:#fff3e0
    style B fill:#e3f2fd
    style C fill:#f3e5f5
    style D fill:#e8f5e8

21. 管道模型 (Pipeline)

详细介绍: 管道模型将请求处理过程分解为多个连续的阶段,每个阶段由专门的线程或线程池负责,形成流水线式的处理架构。
请求按顺序通过各个阶段,每个阶段专注于特定的处理任务,如解析、验证、业务逻辑、响应生成等。 这种模型类似于工厂的流水线生产,能够显著提高系统的吞吐量,因为多个请求可以同时在不同阶段并行处理。
管道模型特别适合处理步骤固定、可以分解的复杂业务流程,在数据处理、图像处理、编译器等领域应用广泛。

实现架构

flowchart TD
    A[Request] --> B[Stage 1 Thread Pool]
    B --> C[Stage 2 Thread Pool]
    C --> D[Stage 3 Thread Pool]
    D --> E[Stage N Thread Pool]
    E --> F[Response]
    
    G[Buffer 1] --> B
    H[Buffer 2] --> C
    I[Buffer 3] --> D
    J[Buffer N] --> E
    
    style B fill:#e1f5fe
    style C fill:#e8f5e8
    style D fill:#fff3e0
    style E fill:#f3e5f5

22. 混合模型

详细介绍: 混合模型是一种综合性的并发架构,根据不同的业务需求和性能要求,在同一个系统中组合使用多种并发模型,可以在I/O处理层使用Reactor模型实现高效的事件处理,在业务逻辑层使用线程池模型保证处理能力,在数据访问层使用异步I/O模型提高数据库访问效率。
这种模型允许开发者针对系统的不同部分选择最适合的并发策略,从而在整体上达到最优的性能表现。
混合模型在大型企业级应用、微服务架构、分布式系统中应用广泛,是现代高性能服务器的主流架构选择。

实现架构

flowchart TD
    A[Model A] --> B[Hybrid Controller]
    C[Model B] --> B
    D[Model C] --> B
    B --> E[Unified Interface]
    
    F[Load Balancer] --> A
    F --> C
    F --> D
    
    style A fill:#e8f5e8
    style C fill:#fff3e0
    style D fill:#e1f5fe
    style B fill:#f3e5f5

编译和运行

编译

make

运行服务器

# 基本用法
./concurrency_server <model> [port]

# 示例
./concurrency_server thread_pool 8080
./concurrency_server epoll 9000
./concurrency_server reactor 8888

测试特定模型

# 测试线程池模型
make test-thread-pool

# 测试epoll模型
make test-epoll

# 测试所有模型(需要手动停止)
make test-single
make test-multi-thread
# ... 等等

性能测试

# 需要安装Apache Bench (ab)
make bench

客户端测试

可以使用多种工具测试服务器:

使用curl

curl http://localhost:8080/

使用Apache Bench

# 1000个请求,10个并发连接
ab -n 1000 -c 10 http://localhost:8080/

使用telnet

telnet localhost 8080
GET / HTTP/1.1
Host: localhost

性能对比

模型名称 QPS
single_process 19075.400
multi_process 6904.800
multi_thread 18137.834
process_pool1 18337.299
process_pool2 18589.268
thread_pool 18483.166
leader_follower 20180.701
poll 18817.867
kqueue 19096.133
reactor 18945.467
event_loop 19442.801
work_stealing 8903.566
actor 18681.500
fiber 18994.268
producer_consumer 18208.633
proactor 18130.533

技术要点

1. 非阻塞I/O

大部分模型都使用了非阻塞I/O来提高性能:

bool set_nonblocking(int fd) {
    int flags = fcntl(fd, F_GETFL, 0);
    if (flags == -1) return false;
    return fcntl(fd, F_SETFL, flags | O_NONBLOCK) != -1;
}

2. 信号处理

进程模型需要处理SIGCHLD信号避免僵尸进程:

signal(SIGCHLD, SIG_IGN);

3. 套接字选项

使用SO_REUSEADDR避免地址重用问题:

int opt = 1;
setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

4. 边缘触发 vs 水平触发

注意事项

  1. 平台兼容性: Epoll仅在Linux上可用,Kqueue仅在BSD/macOS上可用
  2. 资源限制: 注意系统的文件描述符限制和内存限制
  3. 信号处理: 多进程模型需要正确处理子进程信号
  4. 线程安全: 多线程模型需要注意共享资源的同步
  5. 错误处理: 网络编程中要充分考虑各种错误情况

扩展建议

  1. SSL/TLS支持: 添加HTTPS支持
  2. HTTP解析: 完整的HTTP协议解析
  3. 配置文件: 支持配置文件设置参数
  4. 日志系统: 添加完整的日志记录
  5. 监控指标: 添加性能监控和统计
  6. 负载均衡: 实现多服务器负载均衡

学习资源

许可证

本项目仅供学习和研究使用。

Comment