高性能网络框架设计:Reactor模型与epoll事件驱动实现

引言:从石器时代到工业革命——网络编程的进化论

2003年,Dan Kegel发布《The C10K Problem》时,服务器还在用fork()应对并发连接。Apache采用"一连接一线程"模式,当并发突破1万,线程切换开销吞噬了90%的CPU资源。这如同用马车拉高铁——传统阻塞I/O在网络海啸前彻底失灵。

而Reactor模型配合epoll的诞生,让Nginx在2GB内存的机器上轻松处理百万级并发连接。本文将揭秘这套高并发引擎的运作机制,从理论到实战,手把手构建属于你的高性能网络框架!

高性能网络框架的核心价值:

  • 高吞吐量:支持大量并发连接,提升系统的吞吐量。
  • 低延迟:通过高效的事件处理机制,减少响应延迟。
  • 可扩展性:支持水平扩展,适应业务增长的需求。

一、I/O多路复用:从select/poll到epoll的量子跃迁

epoll的工作原理

epoll是Linux系统提供的I/O多路复用接口,用于高效地监控多个文件描述符(如网络套接字)的状态变化。其核心原理包括:

  • 注册事件:将需要监控的文件描述符注册到epoll实例中。
  • 等待事件:阻塞等待I/O事件的发生。
  • 处理事件:根据发生的事件,执行相应的处理逻辑。

2epoll的优势

  • 高效处理大量并发连接:相比select和poll,epoll在处理大量文件描述符时性能更优。
  • 边缘触发模式(EPOLLET):仅在事件状态发生变化时触发通知,减少不必要的事件处理。
  • 支持非阻塞I/O:通过设置文件描述符为非阻塞模式,避免阻塞操作。
理论基石:文件描述符风暴

传统阻塞I/O的瓶颈在于同步等待:当read()调用时,线程被挂起直到数据到达。C10K问题本质是FD(文件描述符)管理效率问题

方案时间复杂度缺点
selectO(n)1024 FD限制
pollO(n)大量FD时性能骤降
epollO(1)无FD上限,高效就绪列表
实战示例:使用epoll实现高效的I/O多路复用
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/epoll.h>

#define MAX_EVENTS 10
#define BUFFER_SIZE 1024

void handle_client(int client_fd) {
    char buffer[BUFFER_SIZE];
    int read_size = read(client_fd, buffer, BUFFER_SIZE - 1);
    if (read_size > 0) {
        printf("Received data: %s\n", buffer);
        // 发送响应
        char response[] = "Hello, Client!";
        send(client_fd, response, strlen(response), 0);
    }
}

int main() {
    int server_fd, epoll_fd;
    struct sockaddr_in server_addr;
    
    // 创建套接字
    server_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (server_fd == -1) {
        perror("socket");
        exit(1);
    }
    
    // 设置套接字选项
    int opt = 1;
    setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
    
    // 绑定地址
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = INADDR_ANY;
    server_addr.sin_port = htons(8080);
    if (bind(server_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {
        perror("bind");
        exit(1);
    }
    
    // 监听连接
    listen(server_fd, 3);
    
    // 创建epoll实例
    epoll_fd = epoll_create1(0);
    if (epoll_fd == -1) {
        perror("epoll_create1");
        exit(1);
    }
    
    // 将服务器套接字添加到epoll监控列表
    struct epoll_event event;
    event.events = EPOLLIN | EPOLLET;
    event.data.fd = server_fd;
    if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, server_fd, &event) == -1) {
        perror("epoll_ctl");
        exit(1);
    }
    
    // 事件循环
    struct epoll_event events[MAX_EVENTS];
    while (1) {
        int event_count = epoll_wait(epoll_fd, events, MAX_EVENTS, -1);
        if (event_count == -1) {
            perror("epoll_wait");
            exit(1);
        }
        
        for (int i = 0; i < event_count; i++) {
            int fd = events[i].data.fd;
            
            if (events[i].events & EPOLLIN) {
                if (fd == server_fd) {
                    // 处理新的连接
                    struct sockaddr_in client_addr;
                    socklen_t client_len = sizeof(client_addr);
                    int client_fd = accept(fd, (struct sockaddr *)&client_addr, &client_len);
                    if (client_fd == -1) {
                        perror("accept");
                        continue;
                    }
                    
                    // 将新连接添加到epoll监控列表
                    struct epoll_event client_event;
                    client_event.events = EPOLLIN | EPOLLET;
                    client_event.data.fd = client_fd;
                    if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, client_fd, &client_event) == -1) {
                        perror("epoll_ctl");
                        close(client_fd);
                        continue;
                    }
                } else {
                    // 处理数据读取
                    handle_client(fd);
                }
            }
        }
    }
    
    // 关闭资源
    close(epoll_fd);
    close(server_fd);
    return 0;
}

epoll的三位一体 

#include <stdio.h>      // 标准输入输出函数
#include <stdlib.h>     // 标准库函数(内存分配、系统命令等)
#include <string.h>     // 字符串处理函数
#include <unistd.h>     // UNIX标准函数(文件操作、进程控制等)
#include <fcntl.h>      // 文件控制选项(非阻塞IO设置)
#include <sys/epoll.h>  // epoll相关函数和数据结构
#include <sys/socket.h> // 套接字编程接口
#include <netinet/in.h> // 互联网地址族定义
#include <arpa/inet.h>  // 互联网地址转换函数

#define MAX_EVENTS 64    // epoll最大事件数
#define PORT 8080       // 服务器监听端口
#define BUFFER_SIZE 1024 // 数据缓冲区大小

// 设置文件描述符为非阻塞模式
void setnonblocking(int fd) {
    int flags = fcntl(fd, F_GETFL, 0); // 获取当前文件状态标志
    fcntl(fd, F_SETFL, flags | O_NONBLOCK); // 添加非阻塞标志
}

int main() {
    // 创建TCP套接字
    int sockfd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0);
    if (sockfd == -1) {
        perror("socket creation failed");
        exit(EXIT_FAILURE);
    }

    // 配置服务器地址
    struct sockaddr_in addr;
    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;          // IPv4地址族
    addr.sin_addr.s_addr = INADDR_ANY;  // 监听所有网络接口
    addr.sin_port = htons(PORT);        // 端口号(主机字节序转网络字节序)

    // 绑定套接字到端口
    if (bind(sockfd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
        perror("bind failed");
        close(sockfd);
        exit(EXIT_FAILURE);
    }

    // 开始监听(设置等待连接队列最大长度)
    if (listen(sockfd, SOMAXCONN) == -1) {
        perror("listen failed");
        close(sockfd);
        exit(EXIT_FAILURE);
    }

    printf("Server listening on port %d...\n", PORT);

    // 创建epoll实例
    // 参数0: 已废弃,内核>2.6.8后自动忽略,保持兼容性
    int epoll_fd = epoll_create1(0);
    if (epoll_fd == -1) {
        perror("epoll_create1 failed");
        close(sockfd);
        exit(EXIT_FAILURE);
    }

    // 配置epoll事件结构
    struct epoll_event ev;
    // 关注可读事件 | 边缘触发模式 | 异常断开检测
    ev.events = EPOLLIN | EPOLLET | EPOLLRDHUP;
    // 关联监听套接字
    ev.data.fd = sockfd;

    // 将监听套接字加入epoll监控
    if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, sockfd, &ev) == -1) {
        perror("epoll_ctl add sockfd failed");
        close(sockfd);
        close(epoll_fd);
        exit(EXIT_FAILURE);
    }

    // 事件循环
    while (1) {
        // 等待事件发生(无限等待)
        struct epoll_event events[MAX_EVENTS];
        int n = epoll_wait(epoll_fd, events, MAX_EVENTS, -1);
        if (n == -1) {
            perror("epoll_wait error");
            break;
        }

        // 处理所有就绪事件
        for (int i = 0; i < n; i++) {
            // 异常断开处理
            if (events[i].events & EPOLLRDHUP) {
                printf("Client disconnected (fd=%d)\n", events[i].data.fd);
                close(events[i].data.fd);
                continue;
            }

            // 监听套接字事件(新连接到达)
            if (events[i].data.fd == sockfd) {
                // 接受所有待处理连接
                while (1) {
                    struct sockaddr_in client_addr;
                    socklen_t addrlen = sizeof(client_addr);
                    // 接受新连接(非阻塞模式)
                    int client_fd = accept4(sockfd, (struct sockaddr*)&client_addr,
                                           &addrlen, SOCK_NONBLOCK);
                    if (client_fd == -1) {
                        // 当没有更多连接时退出循环
                        if (errno == EAGAIN || errno == EWOULDBLOCK) 
                            break;
                        perror("accept failed");
                        break;
                    }

                    // 打印客户端信息
                    char client_ip[INET_ADDRSTRLEN];
                    inet_ntop(AF_INET, &client_addr.sin_addr, client_ip, sizeof(client_ip));
                    printf("New connection from %s:%d (fd=%d)\n", 
                           client_ip, ntohs(client_addr.sin_port), client_fd);

                    // 配置客户端事件
                    struct epoll_event client_ev;
                    // 关注可读事件 | 边缘触发模式 | 异常断开检测
                    client_ev.events = EPOLLIN | EPOLLET | EPOLLRDHUP;
                    client_ev.data.fd = client_fd;

                    // 将新连接加入epoll监控
                    if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, client_fd, &client_ev) == -1) {
                        perror("epoll_ctl add client_fd failed");
                        close(client_fd);
                    }
                }
            }
            // 客户端数据到达
            else if (events[i].events & EPOLLIN) {
                int client_fd = events[i].data.fd;
                char buffer[BUFFER_SIZE];
                
                // ET模式需要循环读取直到数据读完
                while (1) {
                    ssize_t count = read(client_fd, buffer, sizeof(buffer) - 1);
                    if (count == -1) {
                        // 当数据读取完毕时退出循环
                        if (errno == EAGAIN || errno == EWOULDBLOCK) 
                            break;
                        perror("read error");
                        close(client_fd);
                        break;
                    }
                    // 客户端关闭连接
                    else if (count == 0) {
                        printf("Client closed connection (fd=%d)\n", client_fd);
                        close(client_fd);
                        break;
                    }
                    
                    // 处理接收到的数据
                    buffer[count] = '\0';
                    printf("Received from fd=%d: %s\n", client_fd, buffer);
                    
                    // 简易回显服务
                    write(client_fd, buffer, count);
                }
            }
        }
    }

    // 清理资源
    close(sockfd);
    close(epoll_fd);
    return 0;
}

边缘触发(ET) vs 水平触发(LT)

  • ET:状态变化时触发一次,需非阻塞I/O+循环读写

  • LT:就绪状态持续通知,可能引发多次唤醒

验证示例:用epoll实现端口扫描器,对比ET/LT模式下CPU占用率差异


二、Reactor模型解剖:事件驱动的交响乐团

Reactor模型的基本概念

Reactor模型是一种用于处理I/O多路复用的并发处理模型。其核心思想是通过事件驱动的方式,将I/O操作的处理与线程解耦,从而提高系统的吞吐量和响应速度。

2. Reactor模型的组成部分

  • 事件检测器:负责检测I/O事件的发生。
  • 事件分发器:将检测到的事件分发给对应的处理函数。
  • 事件处理器:具体处理I/O事件,执行业务逻辑。

3. Reactor模型的优势

  • 高效处理大量并发连接:通过单线程处理所有I/O事件,避免线程切换的开销。
  • 良好的扩展性:支持水平扩展,适应业务增长的需求。
  • 低延迟:通过事件驱动的方式,快速响应I/O操作。
模型核心四重奏

  1. Reactor:事件循环调度中心

  2. Demultiplexer:epoll实现的事件多路分发器

  3. EventHandler:处理I/O事件的抽象接口

  4. ConcreteHandler:处理具体业务逻辑

实战示例:实现一个简单的Reactor模型

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/epoll.h>

#define MAX_EVENTS 10
#define BUFFER_SIZE 1024

typedef struct {
    int fd;
    char buffer[BUFFER_SIZE];
    size_t buffer_len;
} Connection;

void handle_read(Connection *connection) {
    char buffer[BUFFER_SIZE];
    int read_size = read(connection->fd, buffer, BUFFER_SIZE - 1);
    if (read_size > 0) {
        printf("Received data: %s\n", buffer);
        // 将接收到的数据存储到连接的缓冲区
        memcpy(connection->buffer + connection->buffer_len, buffer, read_size);
        connection->buffer_len += read_size;
    }
}

void handle_write(Connection *connection) {
    if (connection->buffer_len > 0) {
        int write_size = write(connection->fd, connection->buffer, connection->buffer_len);
        if (write_size > 0) {
            // 移除已发送的数据
            memmove(connection->buffer, connection->buffer + write_size, connection->buffer_len - write_size);
            connection->buffer_len -= write_size;
        }
    }
}

int main() {
    int server_fd, epoll_fd;
    struct sockaddr_in server_addr;
    
    // 创建套接字
    server_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (server_fd == -1) {
        perror("socket");
        exit(1);
    }
    
    // 设置套接字选项
    int opt = 1;
    setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
    
    // 绑定地址
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = INADDR_ANY;
    server_addr.sin_port = htons(8080);
    if (bind(server_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {
        perror("bind");
        exit(1);
    }
    
    // 监听连接
    listen(server_fd, 3);
    
    // 创建epoll实例
    epoll_fd = epoll_create1(0);
    if (epoll_fd == -1) {
        perror("epoll_create1");
        exit(1);
    }
    
    // 将服务器套接字添加到epoll监控列表
    struct epoll_event event;
    event.events = EPOLLIN | EPOLLET;
    event.data.fd = server_fd;
    if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, server_fd, &event) == -1) {
        perror("epoll_ctl");
        exit(1);
    }
    
    // 事件循环
    struct epoll_event events[MAX_EVENTS];
    while (1) {
        int event_count = epoll_wait(epoll_fd, events, MAX_EVENTS, -1);
        if (event_count == -1) {
            perror("epoll_wait");
            exit(1);
        }
        
        for (int i = 0; i < event_count; i++) {
            int fd = events[i].data.fd;
            
            if (events[i].events & EPOLLIN) {
                // 处理读事件
                if (fd == server_fd) {
                    // 处理新的连接
                    struct sockaddr_in client_addr;
                    socklen_t client_len = sizeof(client_addr);
                    int client_fd = accept(fd, (struct sockaddr *)&client_addr, &client_len);
                    if (client_fd == -1) {
                        perror("accept");
                        continue;
                    }
                    
                    // 将新连接添加到epoll监控列表
                    struct epoll_event client_event;
                    client_event.events = EPOLLIN | EPOLLET;
                    client_event.data.fd = client_fd;
                    if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, client_fd, &client_event) == -1) {
                        perror("epoll_ctl");
                        close(client_fd);
                        continue;
                    }
                } else {
                    // 处理数据读取
                    Connection *connection = (Connection *)events[i].data.ptr;
                    handle_read(connection);
                }
            }
            
            if (events[i].events & EPOLLOUT) {
                // 处理写事件
                Connection *connection = (Connection *)events[i].data.ptr;
                handle_write(connection);
            }
        }
    }
    
    // 关闭资源
    close(epoll_fd);
    close(server_fd);
    return 0;
}

 

性能倍增秘籍
#include <vector>
#include <memory>
#include <chrono>
#include <sys/epoll.h>  // 使用epoll作为多路复用实现
#include <unistd.h>     // 文件描述符操作

// 前向声明
class EventHandler;

// 事件类型枚举
enum EventType {
    READ_EVENT = EPOLLIN,    // 可读事件
    WRITE_EVENT = EPOLLOUT,  // 可写事件
    ERROR_EVENT = EPOLLERR,  // 错误事件
    HUP_EVENT = EPOLLHUP     // 挂起事件
};

// 多路复用器抽象类(Demultiplexer)
class Demultiplexer {
public:
    virtual ~Demultiplexer() = default;
    
    // 等待事件发生
    virtual int wait(std::vector<struct epoll_event>& events, int timeout) = 0;
    
    // 注册/修改/删除事件监控
    virtual void control(int fd, EventHandler* handler, int ops) = 0;
};

// 事件处理器接口(EventHandler)
class EventHandler {
public:
    virtual ~EventHandler() = default;
    
    // 获取关联的文件描述符
    virtual int get_handle() const = 0;
    
    // 处理事件
    virtual void handle_event(EventType et) = 0;
};

// 基于epoll的具体多路复用器实现
class EpollDemultiplexer : public Demultiplexer {
public:
    EpollDemultiplexer() {
        epoll_fd_ = epoll_create1(0);  // 创建epoll实例
        if (epoll_fd_ == -1) {
            throw std::runtime_error("Failed to create epoll instance");
        }
    }
    
    ~EpollDemultiplexer() override {
        close(epoll_fd_);  // 关闭epoll文件描述符
    }
    
    int wait(std::vector<struct epoll_event>& events, int timeout) override {
        // 等待事件发生
        int num_events = epoll_wait(
            epoll_fd_, 
            events.data(), 
            static_cast<int>(events.size()), 
            timeout
        );
        
        if (num_events == -1 && errno != EINTR) {
            throw std::runtime_error("epoll_wait error");
        }
        
        return num_events;  // 返回就绪事件数量
    }
    
    void control(int fd, EventHandler* handler, int ops) override {
        struct epoll_event ev;
        ev.events = ops;  // 设置关注的事件类型
        ev.data.ptr = handler;  // 关联事件处理器
        
        // 根据操作类型执行相应epoll_ctl操作
        int op = (ops == 0) ? EPOLL_CTL_DEL : EPOLL_CTL_MOD;
        if (epoll_ctl(epoll_fd_, op, fd, &ev) == -1) {
            if (errno == ENOENT) {
                op = EPOLL_CTL_ADD;  // 首次添加
                if (epoll_ctl(epoll_fd_, op, fd, &ev) == -1) {
                    throw std::runtime_error("epoll_ctl add failed");
                }
            } else {
                throw std::runtime_error("epoll_ctl mod/del failed");
            }
        }
    }

private:
    int epoll_fd_;  // epoll文件描述符
};

// Reactor核心类
class Reactor {
public:
    Reactor() : stop_(false) {
        demultiplexer_ = std::make_unique<EpollDemultiplexer>();
    }
    
    // 注册事件处理器
    void register_handler(EventHandler* handler, EventType et) {
        demultiplexer_->control(
            handler->get_handle(), 
            handler, 
            static_cast<int>(et)
        );
    }
    
    // 移除事件处理器
    void remove_handler(EventHandler* handler) {
        demultiplexer_->control(
            handler->get_handle(), 
            nullptr, 
            0
        );
    }
    
    // 启动事件循环
    void run() {
        constexpr int MAX_EVENTS = 64;
        std::vector<struct epoll_event> events(MAX_EVENTS);
        
        // 主事件循环
        while (!stop_) {
            // 计算超时时间(毫秒)
            // -1表示无限等待,0表示立即返回
            int timeout = calculate_timeout();
            
            // 等待事件发生
            int num_events = demultiplexer_->wait(events, timeout);
            
            // 处理所有就绪事件
            for (int i = 0; i < num_events; ++i) {
                // 获取关联的事件处理器
                auto* handler = static_cast<EventHandler*>(events[i].data.ptr);
                
                // 确定具体事件类型
                EventType et = static_cast<EventType>(events[i].events);
                
                // 委托给处理器处理事件
                handler->handle_event(et);
            }
        }
    }
    
    // 停止事件循环
    void stop() { stop_ = true; }

private:
    // 计算下次等待的超时时间
    int calculate_timeout() const {
        // 实际实现中可能考虑:
        // 1. 定时器队列中最接近的到期时间
        // 2. 系统负载情况
        // 3. 是否处于空闲状态
        return -1;  // 默认无限等待
    }

    std::unique_ptr<Demultiplexer> demultiplexer_;  // 多路复用器
    bool stop_;  // 停止标志
};

// 示例:TCP连接处理器
class TcpConnectionHandler : public EventHandler {
public:
    TcpConnectionHandler(int fd) : fd_(fd) {}
    
    int get_handle() const override { return fd_; }
    
    void handle_event(EventType et) override {
        if (et & READ_EVENT) {
            // 处理读事件
            char buffer[1024];
            ssize_t n = read(fd_, buffer, sizeof(buffer));
            if (n > 0) {
                // 处理接收到的数据
                process_data(buffer, n);
            } else if (n == 0) {
                // 连接关闭
                handle_close();
            } else {
                // 读错误
                handle_error();
            }
        }
        
        if (et & WRITE_EVENT) {
            // 处理写事件
            handle_write();
        }
        
        if (et & (ERROR_EVENT | HUP_EVENT)) {
            // 处理错误或连接挂起
            handle_error();
        }
    }

private:
    void process_data(const char* data, size_t len) {
        // 实际业务逻辑处理
    }
    
    void handle_write() {
        // 处理可写事件
    }
    
    void handle_close() {
        // 清理连接资源
        close(fd_);
    }
    
    void handle_error() {
        // 处理错误情况
        close(fd_);
    }

    int fd_;  // 关联的套接字描述符
};

// 使用示例
int main() {
    Reactor reactor;
    
    // 示例:创建一个监听套接字处理器(需实际实现)
    // auto acceptor = std::make_shared<AcceptorHandler>();
    // reactor.register_handler(acceptor.get(), READ_EVENT);
    
    // 启动事件循环
    reactor.run();
    
    return 0;
}

惊群效应解决方案

  • SO_REUSEPORT:内核级负载均衡

  • EPOLLEXCLUSIVE:避免多个进程同时唤醒

验证示例:实现多Reactor线程模型,对比单Reactor性能提升


三、epoll实战:从零构建百万并发框架

核心数据结构设计
// 事件处理器基类
typedef struct {
    int fd;
    void (*read_callback)(void* arg);
    void (*write_callback)(void* arg);
    void* arg;  // 携带业务数据
} EventHandler;

// Reactor主体
typedef struct {
    int epoll_fd;
    EventHandler** handlers;  // FD到处理器的映射
    pthread_mutex_t lock;
} Reactor;
事件注册机制
#include <stdio.h>          // 标准输入输出
#include <stdlib.h>         // 内存分配、系统函数
#include <string.h>         // 字符串处理
#include <unistd.h>         // 文件描述符操作
#include <fcntl.h>          // 文件控制选项
#include <sys/epoll.h>      // epoll 接口
#include <sys/socket.h>     // 套接字接口
#include <pthread.h>        // 线程互斥锁
#include <errno.h>          // 错误码定义

#define MAX_EVENTS 64       // epoll 最大事件数
#define MAX_FDS 1024        // 最大文件描述符数量

// 事件处理器结构体(基类)
typedef struct {
    int fd;                 // 关联的文件描述符
    void (*read_callback)(void* arg);   // 读事件回调函数指针
    void (*write_callback)(void* arg);  // 写事件回调函数指针
    void* arg;              // 传递给回调函数的业务数据
} EventHandler;

// Reactor 核心结构体
typedef struct {
    int epoll_fd;                   // epoll 实例的文件描述符
    EventHandler* handlers[MAX_FDS]; // FD到处理器的映射数组
    pthread_mutex_t lock;           // 线程互斥锁(保护handlers数组)
} Reactor;

// 初始化 Reactor
Reactor* reactor_init() {
    Reactor* reactor = (Reactor*)malloc(sizeof(Reactor));
    if (!reactor) {
        perror("Failed to allocate reactor");
        return NULL;
    }

    // 创建 epoll 实例
    reactor->epoll_fd = epoll_create1(0);
    if (reactor->epoll_fd == -1) {
        perror("Failed to create epoll instance");
        free(reactor);
        return NULL;
    }

    // 初始化 handlers 数组(全部置NULL)
    memset(reactor->handlers, 0, sizeof(reactor->handlers));

    // 初始化互斥锁
    if (pthread_mutex_init(&reactor->lock, NULL) != 0) {
        perror("Failed to initialize mutex");
        close(reactor->epoll_fd);
        free(reactor);
        return NULL;
    }

    return reactor;
}

// 销毁 Reactor
void reactor_destroy(Reactor* reactor) {
    if (!reactor) return;

    // 关闭所有注册的文件描述符(实际项目可能需要更精细的管理)
    for (int i = 0; i < MAX_FDS; i++) {
        if (reactor->handlers[i]) {
            close(i);  // 文件描述符即数组下标
        }
    }

    // 关闭 epoll 实例
    close(reactor->epoll_fd);

    // 销毁互斥锁
    pthread_mutex_destroy(&reactor->lock);

    // 释放 Reactor 内存
    free(reactor);
}

// 向 Reactor 注册事件处理器
int reactor_register(Reactor* reactor, EventHandler* handler, int events) {
    if (!reactor || !handler || handler->fd >= MAX_FDS || handler->fd < 0) {
        return -1;  // 参数检查失败
    }

    // 准备 epoll 事件结构
    struct epoll_event ev;
    ev.events = events;  // 设置关注的事件类型(EPOLLIN | EPOLLOUT 等)
    ev.data.fd = handler->fd;  // 关联文件描述符

    // 线程安全操作(保护handlers数组)
    pthread_mutex_lock(&reactor->lock);

    // 添加/修改 epoll 监控
    int op = reactor->handlers[handler->fd] ? EPOLL_CTL_MOD : EPOLL_CTL_ADD;
    if (epoll_ctl(reactor->epoll_fd, op, handler->fd, &ev) == -1) {
        perror("epoll_ctl operation failed");
        pthread_mutex_unlock(&reactor->lock);
        return -1;
    }

    // 保存处理器到映射数组
    reactor->handlers[handler->fd] = handler;

    pthread_mutex_unlock(&reactor->lock);
    return 0;
}

// 从 Reactor 注销事件处理器
int reactor_unregister(Reactor* reactor, int fd) {
    if (!reactor || fd >= MAX_FDS || fd < 0) {
        return -1;  // 参数检查失败
    }

    pthread_mutex_lock(&reactor->lock);

    // 从 epoll 移除监控
    if (epoll_ctl(reactor->epoll_fd, EPOLL_CTL_DEL, fd, NULL) == -1) {
        perror("epoll_ctl delete failed");
        pthread_mutex_unlock(&reactor->lock);
        return -1;
    }

    // 清除处理器映射
    reactor->handlers[fd] = NULL;

    pthread_mutex_unlock(&reactor->lock);
    return 0;
}

// Reactor 事件循环
void reactor_run(Reactor* reactor) {
    if (!reactor) return;

    struct epoll_event events[MAX_EVENTS];

    printf("Reactor started running...\n");

    while (1) {
        // 等待事件发生(无限等待)
        int nfds = epoll_wait(reactor->epoll_fd, events, MAX_EVENTS, -1);
        if (nfds == -1) {
            // 被信号中断则继续等待
            if (errno == EINTR) continue;
            perror("epoll_wait error");
            break;
        }

        // 处理所有就绪事件
        for (int i = 0; i < nfds; i++) {
            int fd = events[i].data.fd;
            int revents = events[i].events;

            // 线程安全获取处理器(防止处理过程中被注销)
            pthread_mutex_lock(&reactor->lock);
            EventHandler* handler = reactor->handlers[fd];
            pthread_mutex_unlock(&reactor->lock);

            if (!handler) continue;  // 处理器已被注销

            // 处理读事件(且确实有读回调)
            if ((revents & EPOLLIN) && handler->read_callback) {
                handler->read_callback(handler->arg);
            }

            // 处理写事件(且确实有写回调)
            if ((revents & EPOLLOUT) && handler->write_callback) {
                handler->write_callback(handler->arg);
            }

            // 处理错误事件(EPOLLERR | EPOLLHUP)
            if (revents & (EPOLLERR | EPOLLHUP)) {
                if (handler->read_callback) {
                    handler->read_callback(handler->arg);  // 通常用读回调处理错误
                }
                reactor_unregister(reactor, fd);  // 自动注销
                close(fd);  // 关闭文件描述符
            }
        }
    }
}

/********************** 示例使用代码 **********************/

// 业务数据示例结构
typedef struct {
    int fd;
    char buffer[1024];
} ClientData;

// 读事件回调示例
void on_client_read(void* arg) {
    ClientData* data = (ClientData*)arg;
    ssize_t n = read(data->fd, data->buffer, sizeof(data->buffer) - 1);
    
    if (n > 0) {
        data->buffer[n] = '\0';
        printf("Received from fd=%d: %s\n", data->fd, data->buffer);
        
        // 简易回显
        write(data->fd, data->buffer, n);
    } else if (n == 0) {
        printf("Client fd=%d disconnected\n", data->fd);
        close(data->fd);  // Reactor会自动注销
    } else {
        perror("read error");
        close(data->fd);  // Reactor会自动注销
    }
}

// 写事件回调示例(略)
void on_client_write(void* arg) {
    // 实际项目中处理写完成事件
}

int main() {
    // 创建并初始化 Reactor
    Reactor* reactor = reactor_init();
    if (!reactor) {
        return 1;
    }

    // 示例:创建监听套接字(实际项目需要完整实现)
    int listen_fd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0);
    if (listen_fd == -1) {
        perror("socket creation failed");
        reactor_destroy(reactor);
        return 1;
    }

    // 绑定和监听(简略实现)
    struct sockaddr_in addr = {0};
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = INADDR_ANY;
    addr.sin_port = htons(8080);
    
    if (bind(listen_fd, (struct sockaddr*)&addr, sizeof(addr)) {
        perror("bind failed");
        close(listen_fd);
        reactor_destroy(reactor);
        return 1;
    }
    
    if (listen(listen_fd, SOMAXCONN)) {
        perror("listen failed");
        close(listen_fd);
        reactor_destroy(reactor);
        return 1;
    }

    // 创建监听套接字的处理器
    EventHandler* acceptor = (EventHandler*)malloc(sizeof(EventHandler));
    ClientData* acceptor_data = (ClientData*)malloc(sizeof(ClientData));
    
    acceptor->fd = listen_fd;
    acceptor->read_callback = on_client_read;  // 接受新连接也用读回调
    acceptor->write_callback = NULL;
    acceptor->arg = acceptor_data;
    
    acceptor_data->fd = listen_fd;

    // 注册到 Reactor(关注读事件)
    if (reactor_register(reactor, acceptor, EPOLLIN) != 0) {
        fprintf(stderr, "Failed to register acceptor handler\n");
        close(listen_fd);
        free(acceptor_data);
        free(acceptor);
        reactor_destroy(reactor);
        return 1;
    }

    // 启动事件循环
    reactor_run(reactor);

    // 清理资源(正常情况下不会执行到这里)
    reactor_destroy(reactor);
    return 0;
}
ET模式下的读写黄金法则
#include <stdio.h>          // 标准输入输出
#include <stdlib.h>         // 内存分配、系统函数
#include <string.h>         // 字符串处理
#include <unistd.h>         // 文件描述符操作
#include <fcntl.h>          // 文件控制选项
#include <sys/epoll.h>      // epoll 接口
#include <sys/socket.h>     // 套接字接口
#include <pthread.h>        // 线程互斥锁
#include <errno.h>          // 错误码定义
#include <stdint.h>         // 标准整数类型

#define MAX_EVENTS 64       // epoll 最大事件数
#define MAX_FDS 1024        // 最大文件描述符数量

// 事件处理器结构体(基类)
typedef struct {
    int fd;                 // 关联的文件描述符
    void (*read_callback)(void* arg);   // 读事件回调函数指针
    void (*write_callback)(void* arg);  // 写事件回调函数指针
    void* arg;              // 传递给回调函数的业务数据
} EventHandler;

// Reactor 核心结构体
typedef struct {
    int epoll_fd;                   // epoll 实例的文件描述符
    EventHandler* handlers[MAX_FDS]; // FD到处理器的映射数组
    pthread_mutex_t lock;           // 线程互斥锁(保护handlers数组)
} Reactor;

// 初始化 Reactor
Reactor* reactor_init() {
    Reactor* r = (Reactor*)malloc(sizeof(Reactor));
    if (!r) {
        perror("malloc for reactor failed");
        return NULL;
    }

    // 创建 epoll 实例
    r->epoll_fd = epoll_create1(0);
    if (r->epoll_fd == -1) {
        perror("epoll_create1 failed");
        free(r);
        return NULL;
    }

    // 初始化 handlers 数组(全部置NULL)
    memset(r->handlers, 0, sizeof(r->handlers));

    // 初始化互斥锁(快速锁,无属性)
    if (pthread_mutex_init(&r->lock, NULL) != 0) {
        perror("pthread_mutex_init failed");
        close(r->epoll_fd);
        free(r);
        return NULL;
    }

    return r;
}

// 添加事件处理器到 Reactor(边缘触发模式)
// 参数说明:
//   r - Reactor 实例指针
//   h - 事件处理器指针
//   events - 需要监听的事件组合(EPOLLIN | EPOLLOUT 等)
void reactor_add(Reactor* r, EventHandler* h, uint32_t events) {
    // 创建 epoll 事件结构并清零
    struct epoll_event ev = {0};
    
    // 设置事件类型:用户指定的事件 + 强制边缘触发模式
    // EPOLLET 标志表示使用边缘触发(Edge Triggered)模式
    ev.events = events | EPOLLET;  
    
    // 将事件处理器指针存入 data 字段(后续可通过ptr找回handler)
    ev.data.ptr = h;
    
    // 加锁保护共享资源(handlers数组和epoll_ctl操作)
    pthread_mutex_lock(&r->lock);
    
    // 将文件描述符添加到 epoll 监控
    // EPOLL_CTL_ADD 表示添加新的监控项
    if (epoll_ctl(r->epoll_fd, EPOLL_CTL_ADD, h->fd, &ev) == -1) {
        // 如果添加失败,可能是fd已经存在,尝试修改
        if (errno == EEXIST) {
            if (epoll_ctl(r->epoll_fd, EPOLL_CTL_MOD, h->fd, &ev) == -1) {
                perror("epoll_ctl mod failed");
                pthread_mutex_unlock(&r->lock);
                return;
            }
        } else {
            perror("epoll_ctl add failed");
            pthread_mutex_unlock(&r->lock);
            return;
        }
    }
    
    // 将处理器存入 handlers 数组(以fd为索引)
    r->handlers[h->fd] = h;
    
    // 解锁
    pthread_mutex_unlock(&r->lock);
}

// 从 Reactor 移除事件处理器
void reactor_remove(Reactor* r, int fd) {
    // 参数检查
    if (fd < 0 || fd >= MAX_FDS) {
        fprintf(stderr, "Invalid fd: %d\n", fd);
        return;
    }

    pthread_mutex_lock(&r->lock);
    
    // 从 epoll 移除监控
    if (epoll_ctl(r->epoll_fd, EPOLL_CTL_DEL, fd, NULL) == -1) {
        perror("epoll_ctl del failed");
    }
    
    // 清除 handlers 数组中的记录
    r->handlers[fd] = NULL;
    
    pthread_mutex_unlock(&r->lock);
}

// 修改已注册的事件类型
void reactor_modify(Reactor* r, EventHandler* h, uint32_t events) {
    struct epoll_event ev = {0};
    ev.events = events | EPOLLET;  // 保持边缘触发模式
    ev.data.ptr = h;
    
    pthread_mutex_lock(&r->lock);
    
    // 修改现有监控项
    if (epoll_ctl(r->epoll_fd, EPOLL_CTL_MOD, h->fd, &ev) == -1) {
        perror("epoll_ctl modify failed");
    }
    
    pthread_mutex_unlock(&r->lock);
}

// 运行 Reactor 事件循环
void reactor_run(Reactor* r) {
    if (!r) return;

    struct epoll_event events[MAX_EVENTS];
    
    printf("Reactor event loop started (ET mode)\n");
    
    while (1) {
        // 等待事件发生(无限等待)
        int n = epoll_wait(r->epoll_fd, events, MAX_EVENTS, -1);
        if (n == -1) {
            if (errno == EINTR) continue;  // 被信号中断则重试
            perror("epoll_wait error");
            break;
        }

        // 处理所有就绪事件
        for (int i = 0; i < n; i++) {
            // 从事件数据中获取处理器指针
            EventHandler* h = (EventHandler*)events[i].data.ptr;
            uint32_t revents = events[i].events;
            
            // 检查处理器有效性(可能已被移除)
            pthread_mutex_lock(&r->lock);
            int valid = (h && r->handlers[h->fd] == h);
            pthread_mutex_unlock(&r->lock);
            
            if (!valid) continue;
            
            // 边缘触发模式必须处理所有可用数据
            if ((revents & EPOLLIN) && h->read_callback) {
                // 循环读取直到EAGAIN(非阻塞IO必需)
                while (1) {
                    h->read_callback(h->arg);
                    
                    // 实际项目中需要检查是否还有数据可读
                    // 可以通过额外系统调用判断,这里简化为单次回调
                    break;
                }
            }
            
            if ((revents & EPOLLOUT) && h->write_callback) {
                h->write_callback(h->arg);
            }
            
            // 处理错误和挂起事件
            if (revents & (EPOLLERR | EPOLLHUP | EPOLLRDHUP)) {
                if (h->read_callback) {
                    h->read_callback(h->arg);  // 通常用读回调处理错误
                }
                reactor_remove(r, h->fd);  // 自动移除
                close(h->fd);  // 关闭文件描述符
            }
        }
    }
}

// 销毁 Reactor
void reactor_destroy(Reactor* r) {
    if (!r) return;
    
    // 清理所有处理器
    for (int i = 0; i < MAX_FDS; i++) {
        if (r->handlers[i]) {
            close(i);  // 关闭文件描述符
            free(r->handlers[i]->arg);  // 释放业务数据
            free(r->handlers[i]);  // 释放处理器
        }
    }
    
    close(r->epoll_fd);
    pthread_mutex_destroy(&r->lock);
    free(r);
}

/********************** 示例使用 **********************/

typedef struct {
    int fd;
    char buf[1024];
} ClientData;

void on_read(void* arg) {
    ClientData* data = (ClientData*)arg;
    ssize_t n = read(data->fd, data->buf, sizeof(data->buf)-1);
    
    if (n > 0) {
        data->buf[n] = 0;
        printf("FD %d: %s\n", data->fd, data->buf);
        write(data->fd, data->buf, n);  // 回显
    } else if (n == 0 || errno == EAGAIN) {
        // ET模式需处理EAGAIN
    } else {
        perror("read error");
    }
}

int main() {
    // 创建Reactor实例
    Reactor* r = reactor_init();
    
    // 示例:创建TCP服务器(简略版)
    int listen_fd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0);
    struct sockaddr_in addr = { .sin_family=AF_INET, .sin_port=htons(8080), .sin_addr.s_addr=INADDR_ANY };
    bind(listen_fd, (struct sockaddr*)&addr, sizeof(addr));
    listen(listen_fd, SOMAXCONN);
    
    // 创建监听处理器
    EventHandler* h = malloc(sizeof(EventHandler));
    ClientData* data = malloc(sizeof(ClientData));
    data->fd = listen_fd;
    h->fd = listen_fd;
    h->read_callback = on_read;
    h->write_callback = NULL;
    h->arg = data;
    
    // 添加到Reactor(边缘触发读事件)
    reactor_add(r, h, EPOLLIN);
    
    // 运行事件循环
    reactor_run(r);
    
    // 清理(正常情况下不会执行到这里)
    reactor_destroy(r);
    return 0;
}

验证示例:实现ECHO服务器,测试10K并发连接下数据传输完整性


四、性能优化:突破百万并发的核武器

锁优化三剑客

内存池设计
零拷贝技术矩阵
技术原理性能提升
sendfile内核直接传输文件40%
splice管道中转数据30%
TCP_CORK合并小数据包25%
  1. 无锁队列:使用__sync_fetch_and_add实现任务分发

    #include <stdio.h>      // 标准输入输出
    #include <stdlib.h>     // 内存分配
    #include <stdint.h>     // 标准整数类型
    #include <unistd.h>     // 系统调用
    
    #define MAX_TASKS 1024  // 任务队列最大容量
    
    // 任务结构体定义
    typedef struct {
        void (*function)(void*);  // 任务函数指针
        void* arg;               // 任务参数
    } Task;
    
    // 线程安全环形队列结构体
    typedef struct {
        Task tasks[MAX_TASKS];    // 任务数组
        volatile uint32_t head;   // 队列头指针(原子访问)
        volatile uint32_t tail;   // 队列尾指针(原子访问)
    } TaskQueue;
    
    // 初始化任务队列
    void init_queue(TaskQueue* q) {
        q->head = 0;  // 初始化头指针为0
        q->tail = 0;  // 初始化尾指针为0
        
        // 清空任务数组(可选)
        for (int i = 0; i < MAX_TASKS; i++) {
            q->tasks[i].function = NULL;
            q->tasks[i].arg = NULL;
        }
    }
    
    // 原子操作添加任务到队列
    // 参数:
    //   q - 任务队列指针
    //   t - 要添加的任务
    void push_task(TaskQueue* q, Task t) {
        // 使用原子操作获取当前tail值并自增1
        // __sync_fetch_and_add是GCC内置原子操作函数:
        // 1. 先返回q->tail的当前值
        // 2. 然后将q->tail的值增加1
        // 这个操作在多线程环境下是原子的
        int idx = __sync_fetch_and_add(&q->tail, 1) % MAX_TASKS;
        
        // 将任务写入计算得到的位置
        // 注意:这里没有检查队列是否已满,实际使用时需要添加容量检查
        q->tasks[idx] = t;
    }
    
    // 原子操作从队列取出任务
    // 参数:
    //   q - 任务队列指针
    // 返回:
    //   成功返回任务,队列为空返回空任务(function为NULL)
    Task pop_task(TaskQueue* q) {
        // 使用原子操作获取当前head值
        uint32_t current_head = __sync_fetch_and_add(&q->head, 0);
        
        // 检查队列是否为空
        if (current_head == __sync_fetch_and_add(&q->tail, 0)) {
            Task empty_task = { NULL, NULL };
            return empty_task;  // 队列为空
        }
        
        // 计算实际索引(环形缓冲区)
        int idx = current_head % MAX_TASKS;
        
        // 读取任务
        Task t = q->tasks[idx];
        
        // 使用原子操作移动head指针
        __sync_fetch_and_add(&q->head, 1);
        
        return t;
    }
    
    // 检查队列是否为空
    int is_queue_empty(TaskQueue* q) {
        // 原子读取head和tail值进行比较
        return __sync_fetch_and_add(&q->head, 0) == 
               __sync_fetch_and_add(&q->tail, 0);
    }
    
    // 示例任务函数
    void example_task(void* arg) {
        int* num = (int*)arg;
        printf("Processing task with number: %d\n", *num);
    }
    
    int main() {
        TaskQueue queue;
        init_queue(&queue);
    
        // 示例:添加任务
        int arg1 = 42, arg2 = 100;
        
        Task t1 = { example_task, &arg1 };
        Task t2 = { example_task, &arg2 };
        
        // 线程安全地添加任务
        push_task(&queue, t1);
        push_task(&queue, t2);
        
        // 处理任务
        while (!is_queue_empty(&queue)) {
            Task t = pop_task(&queue);
            if (t.function) {
                t.function(t.arg);  // 执行任务
            }
        }
        
        return 0;
    }

  2. RCU(Read-Copy-Update):减少处理器映射的锁竞争

  3. FD分片:按FD哈希值分配到不同Reactor线程

#include <stdio.h>      // 标准输入输出
#include <stdlib.h>     // 内存分配
#include <string.h>     // 内存操作

#define MAX_BLOCKS 1024 // 内存池最大块数
#define BLOCK_SIZE 4096 // 每个内存块大小(4KB)

// 内存池结构体
typedef struct {
    void* blocks[MAX_BLOCKS];  // 内存块指针数组
    int free_list[MAX_BLOCKS]; // 空闲块索引栈
    int top;                  // 空闲栈顶指针
    size_t block_size;        // 每个块的大小
    int initialized;          // 初始化标志
} MemPool;

// 初始化内存池
// 参数:
//   pool - 内存池指针
//   block_size - 每个内存块的大小
void mempool_init(MemPool* pool, size_t block_size) {
    // 检查参数有效性
    if (pool == NULL || block_size == 0) {
        fprintf(stderr, "Invalid parameters\n");
        return;
    }

    // 初始化成员变量
    memset(pool->blocks, 0, sizeof(pool->blocks));  // 清空块指针数组
    memset(pool->free_list, 0, sizeof(pool->free_list)); // 清空空闲列表
    
    pool->top = 0;            // 初始时栈顶为0(栈空)
    pool->block_size = block_size; // 设置块大小
    pool->initialized = 1;    // 标记为已初始化

    // 预分配所有内存块
    for (int i = 0; i < MAX_BLOCKS; i++) {
        pool->blocks[i] = malloc(block_size);  // 分配内存块
        if (pool->blocks[i] == NULL) {
            perror("Failed to allocate memory block");
            // 如果分配失败,继续初始化已成功的块
            break;
        }
        // 将块索引压入空闲栈
        pool->free_list[pool->top++] = i;
    }
}

// 从内存池分配内存块
// 参数:
//   pool - 内存池指针
// 返回:
//   成功返回内存块指针,失败返回NULL
void* mempool_alloc(MemPool* pool) {
    // 检查内存池是否初始化
    if (!pool || !pool->initialized) {
        fprintf(stderr, "Memory pool not initialized\n");
        return NULL;
    }

    // 检查空闲栈中是否有可用块
    if (pool->top > 0) {
        // 从空闲栈弹出顶部索引(后进先出)
        int block_idx = pool->free_list[--pool->top];
        // 返回对应的内存块
        return pool->blocks[block_idx];
    }

    // 空闲栈为空,直接分配新内存(超出池容量)
    void* new_block = malloc(pool->block_size);
    if (new_block) {
        printf("Warning: Allocated beyond pool capacity\n");
    }
    return new_block;
}

// 释放内存块回内存池
// 参数:
//   pool - 内存池指针
//   ptr - 要释放的内存块指针
void mempool_free(MemPool* pool, void* ptr) {
    // 检查参数有效性
    if (!pool || !ptr || !pool->initialized) {
        fprintf(stderr, "Invalid parameters\n");
        return;
    }

    // 检查指针是否属于内存池
    int is_pool_block = 0;
    int block_idx = -1;
    
    // 遍历所有块查找匹配指针
    for (int i = 0; i < MAX_BLOCKS; i++) {
        if (pool->blocks[i] == ptr) {
            is_pool_block = 1;
            block_idx = i;
            break;
        }
    }

    if (is_pool_block) {
        // 如果指针属于内存池,将块索引压回空闲栈
        if (pool->top < MAX_BLOCKS) {
            pool->free_list[pool->top++] = block_idx;
        } else {
            fprintf(stderr, "Free list overflow\n");
        }
    } else {
        // 不属于内存池的指针直接释放
        free(ptr);
    }
}

// 销毁内存池
void mempool_destroy(MemPool* pool) {
    if (!pool || !pool->initialized) return;

    // 释放所有内存块
    for (int i = 0; i < MAX_BLOCKS; i++) {
        if (pool->blocks[i]) {
            free(pool->blocks[i]);
            pool->blocks[i] = NULL;
        }
    }

    // 重置内存池状态
    pool->top = 0;
    pool->initialized = 0;
}

// 示例使用
int main() {
    MemPool pool;
    
    // 初始化内存池(4KB块大小)
    mempool_init(&pool, BLOCK_SIZE);
    
    // 分配内存块
    void* block1 = mempool_alloc(&pool);
    void* block2 = mempool_alloc(&pool);
    
    if (block1 && block2) {
        printf("Allocated blocks: %p and %p\n", block1, block2);
        
        // 使用内存块(示例)
        strcpy((char*)block1, "Hello from memory pool");
        printf("Block1 content: %s\n", (char*)block1);
        
        // 释放内存块
        mempool_free(&pool, block1);
        mempool_free(&pool, block2);
    }
    
    // 销毁内存池
    mempool_destroy(&pool);
    return 0;
}

验证示例:实现内存泄漏检测系统,对比优化前后内存碎片率


五、从Reactor到Proactor:异步I/O的圣杯

Reactor的局限性
  • 仍依赖同步I/O操作

  • 磁盘I/O可能阻塞事件循环

Proactor架构跃迁

Linux AIO实战
#include <stdio.h>          // 标准输入输出
#include <stdlib.h>         // 内存分配
#include <string.h>         // 字符串操作
#include <fcntl.h>         // 文件控制选项
#include <unistd.h>        // UNIX标准函数
#include <libaio.h>        // Linux异步I/O库
#include <errno.h>         // 错误码定义
#include <inttypes.h>      // 整数类型定义

#define BUFFER_SIZE 4096   // 读写缓冲区大小

int main(int argc, char *argv[]) {
    // 检查参数是否正确(需要文件名参数)
    if (argc != 2) {
        fprintf(stderr, "Usage: %s <filename>\n", argv[0]);
        return 1;
    }

    // 1. 创建异步I/O上下文
    io_context_t aio_ctx = 0;
    if (io_setup(10, &aio_ctx) < 0) {  // 参数10表示同时支持的最大请求数
        perror("io_setup failed");
        return 1;
    }

    // 2. 打开目标文件(以只读方式)
    int fd = open(argv[1], O_RDONLY | O_DIRECT);  // O_DIRECT启用直接I/O(绕过缓存)
    if (fd < 0) {
        perror("open failed");
        io_destroy(aio_ctx);
        return 1;
    }

    // 3. 准备数据缓冲区(直接I/O需要内存对齐)
    void *buffer = NULL;
    if (posix_memalign(&buffer, 512, BUFFER_SIZE) != 0) {  // 512字节对齐
        perror("posix_memalign failed");
        close(fd);
        io_destroy(aio_ctx);
        return 1;
    }
    memset(buffer, 0, BUFFER_SIZE);  // 清空缓冲区

    // 4. 准备I/O控制块(iocb)
    struct iocb cb = {0};  // 清零初始化
    cb.aio_fildes = fd;    // 设置文件描述符
    cb.aio_lio_opcode = IOCB_CMD_PREAD;  // 异步读操作
    cb.aio_buf = (uint64_t)buffer;  // 数据缓冲区地址(转换为64位)
    cb.aio_nbytes = BUFFER_SIZE;    // 读取的字节数
    cb.aio_offset = 0;              // 从文件开头读取

    // 5. 提交异步I/O请求
    struct iocb *cbs[1] = {&cb};   // 请求指针数组
    if (io_submit(aio_ctx, 1, cbs) != 1) {  // 提交1个请求
        perror("io_submit failed");
        free(buffer);
        close(fd);
        io_destroy(aio_ctx);
        return 1;
    }

    // 6. 等待I/O操作完成
    struct io_event events[1];  // 事件数组
    int ret = io_getevents(aio_ctx, 1, 1, events, NULL);  // 等待1个事件完成
    if (ret != 1) {
        perror("io_getevents failed");
        free(buffer);
        close(fd);
        io_destroy(aio_ctx);
        return 1;
    }

    // 7. 检查操作结果
    if (events[0].res != BUFFER_SIZE) {
        fprintf(stderr, "Read incomplete: %lld bytes\n", (long long)events[0].res);
    } else {
        printf("Successfully read %d bytes\n", BUFFER_SIZE);
        // 打印前16字节内容(示例)
        printf("First 16 bytes: ");
        for (int i = 0; i < 16; i++) {
            printf("%02x ", ((unsigned char*)buffer)[i]);
        }
        printf("\n");
    }

    // 8. 清理资源
    free(buffer);
    close(fd);
    io_destroy(aio_ctx);  // 销毁异步I/O上下文

    return 0;
}

六、Reactor模型与epoll的结合:高性能网络框架的实现

1. Reactor模型与epoll的结合

通过将Reactor模型与epoll结合,可以实现一个高效的网络框架。Reactor模型负责事件的分发和处理,而epoll负责高效的I/O多路复用。

2. 实现高性能网络框架的关键点

  • 线程模型的选择:选择单线程模型,通过Reactor模型处理所有I/O事件。
  • 非阻塞I/O:通过设置文件描述符为非阻塞模式,避免阻塞操作。
  • 高效的事件处理:通过事件驱动的方式,快速响应I/O事件。

实战示例:实现一个高性能的网络服务器框架 

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/epoll.h>
#include <pthread.h>

#define MAX_EVENTS 10
#define BUFFER_SIZE 1024

typedef struct {
    int fd;
    char buffer[BUFFER_SIZE];
    size_t buffer_len;
    pthread_t thread_id;
} Connection;

void *connection_handler(void *arg) {
    Connection *connection = (Connection *)arg;
    
    while (1) {
        char buffer[BUFFER_SIZE];
        int read_size = read(connection->fd, buffer, BUFFER_SIZE - 1);
        if (read_size > 0) {
            printf("Received data from %d: %s\n", connection->fd, buffer);
            // 将接收到的数据存储到连接的缓冲区
            memcpy(connection->buffer + connection->buffer_len, buffer, read_size);
            connection->buffer_len += read_size;
        }
        
        if (connection->buffer_len > 0) {
            int write_size = write(connection->fd, connection->buffer, connection->buffer_len);
            if (write_size > 0) {
                // 移除已发送的数据
                memmove(connection->buffer, connection->buffer + write_size, connection->buffer_len - write_size);
                connection->buffer_len -= write_size;
            }
        }
    }
    
    close(connection->fd);
    free(connection);
    return NULL;
}

int main() {
    int server_fd, epoll_fd;
    struct sockaddr_in server_addr;
    
    // 创建套接字
    server_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (server_fd == -1) {
        perror("socket");
        exit(1);
    }
    
    // 设置套接字选项
    int opt = 1;
    setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
    
    // 绑定地址
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = INADDR_ANY;
    server_addr.sin_port = htons(8080);
    if (bind(server_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {
        perror("bind");
        exit(1);
    }
    
    // 监听连接
    listen(server_fd, 3);
    
    // 创建epoll实例
    epoll_fd = epoll_create1(0);
    if (epoll_fd == -1) {
        perror("epoll_create1");
        exit(1);
    }
    
    // 将服务器套接字添加到epoll监控列表
    struct epoll_event event;
    event.events = EPOLLIN | EPOLLET;
    event.data.fd = server_fd;
    if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, server_fd, &event) == -1) {
        perror("epoll_ctl");
        exit(1);
    }
    
    // 事件循环
    struct epoll_event events[MAX_EVENTS];
    while (1) {
        int event_count = epoll_wait(epoll_fd, events, MAX_EVENTS, -1);
        if (event_count == -1) {
            perror("epoll_wait");
            exit(1);
        }
        
        for (int i = 0; i < event_count; i++) {
            int fd = events[i].data.fd;
            
            if (events[i].events & EPOLLIN) {
                if (fd == server_fd) {
                    // 处理新的连接
                    struct sockaddr_in client_addr;
                    socklen_t client_len = sizeof(client_addr);
                    int client_fd = accept(fd, (struct sockaddr *)&client_addr, &client_len);
                    if (client_fd == -1) {
                        perror("accept");
                        continue;
                    }
                    
                    // 创建新的连接结构体
                    Connection *connection = (Connection *)malloc(sizeof(Connection));
                    connection->fd = client_fd;
                    connection->buffer_len = 0;
                    
                    // 创建新的线程处理连接
                    if (pthread_create(&connection->thread_id, NULL, connection_handler, connection) != 0) {
                        perror("pthread_create");
                        close(client_fd);
                        free(connection);
                        continue;
                    }
                } else {
                    // 处理数据读取
                    // (实际应用中,可以通过epoll_wait获取到连接的文件描述符,并分发给对应的线程处理)
                }
            }
        }
    }
    
    // 关闭资源
    close(epoll_fd);
    close(server_fd);
    return 0;
}

结语:永恒的性能追求

从C10K到C10M,Reactor+epoll的组合仍是Linux高性能网络的基石。Nginx、Redis、Memcached等顶级开源项目无不以此为核心:

  1. Nginx:多Reactor进程+定时器红黑树

  2. Redis:单Reactor+多I/O线程

  3. DPDK:用户态协议栈+epoll模拟

但技术从未停止进化:io_uring正在颠覆传统异步I/O模型,eBPF让网络栈可编程化... 掌握核心原理,方能以不变应万变!

终极挑战:结合io_uring重构Reactor核心,实现200万QPS代理服务器

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

司铭鸿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值