C++从0实现百万并发Reactor服务器
获取ZY↑↑方打开链接↑↑
实现一个支持百万并发连接的 Reactor 模型服务器是一个复杂的过程,需要考虑很多细节和技术。下面是一个从零开始构建这样一个服务器的基本步骤和关键点。我们将使用 C++ 和 Linux 的 epoll 机制来实现。
1. 确定需求
首先,明确服务器需要支持的功能和服务类型。例如,这是一个简单的 TCP 服务器还是一个更复杂的 HTTP 服务器?需要支持哪些具体的协议?
2. 设计架构
2.1 Reactor 模型概述
Reactor 模型是一种事件驱动的设计模式,其中有一个或多个线程等待事件的发生,然后将事件分发给相应的处理函数。
2.2 核心组件
- Event Dispatcher (Reactor) :负责接收事件并分发给相应的处理函数。
- Event Handlers:负责处理具体的事件。
- Worker Threads:处理事件的实际工作。
3. 使用 epoll
epoll 是 Linux 下高效的 I/O 多路复用机制,非常适合用于构建高性能服务器。
3.1 初始化 epoll
cpp浅色版本#include <sys/epoll.h>#include <unistd.h>#include <iostream>int main() { int epoll_fd = epoll_create(1); // 创建 epoll 实例 if (epoll_fd == -1) { std::cerr << "Failed to create epoll instance." << std::endl; return -1; } // 后续代码...}
3.2 创建监听 socket
cpp浅色版本#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>int listen_sock = socket(AF_INET, SOCK_STREAM, 0); // 创建 socketif (listen_sock == -1) { std::cerr << "Failed to create socket." << std::endl; return -1;}struct sockaddr_in serv_addr;serv_addr.sin_family = AF_INET;serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);serv_addr.sin_port = htons(8080); // 设置监听端口if (bind(listen_sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) == -1) { std::cerr << "Failed to bind socket." << std::endl; return -1;}if (listen(listen_sock, 5) == -1) { std::cerr << "Failed to listen on socket." << std::endl; return -1;}// 将监听 socket 添加到 epoll 实例中struct epoll_event ev;ev.events = EPOLLIN; // 监听读事件ev.data.fd = listen_sock;if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, listen_sock, &ev) == -1) { std::cerr << "Failed to add socket to epoll." << std::endl; return -1;}
4. Reactor 模型实现
4.1 定义事件处理类
cpp浅色版本class EventHandler {public: virtual void handleRead() = 0; virtual void handleWrite() = 0;};
4.2 Reactor 类
cpp浅色版本class Reactor {private: int epoll_fd_; std::unordered_map<int, EventHandler*> handlers_;public: Reactor() : epoll_fd_(epoll_create(1)) {} ~Reactor() { close(epoll_fd_); } void addHandler(int fd, EventHandler* handler) { handlers_[fd] = handler; struct epoll_event ev; ev.events = EPOLLIN | EPOLLET; // 边缘触发模式 ev.data.ptr = handler; epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, fd, &ev); } void removeHandler(int fd) { epoll_ctl(epoll_fd_, EPOLL_CTL_DEL, fd, nullptr); handlers_.erase(fd); } void loop() { std::vector<epoll_event> events(MAX_EVENTS); // MAX_EVENTS 是你期望的最大事件数 while (true) { int num_events = epoll_wait(epoll_fd_, events.data(), events.size(), -1); if (num_events == -1) { std::cerr << "Failed to wait for epoll events." << std::endl; continue; } for (int i = 0; i < num_events; ++i) { auto handler = static_cast<EventHandler*>(events[i].data.ptr); if (events[i].events & EPOLLIN) { handler->handleRead(); } if (events[i].events & EPOLLOUT) { handler->handleWrite(); } } } }};
4.3 客户端连接处理
cpp浅色版本void accept_connection(int listen_sock, Reactor& reactor) { int conn_sock = accept(listen_sock, nullptr, nullptr); if (conn_sock == -1) { std::cerr << "Failed to accept connection." << std::endl; return; } // 设置为非阻塞模式 fcntl(conn_sock, F_SETFL, O_NONBLOCK); // 创建事件处理器实例 auto handler = new ClientHandler(conn_sock); reactor.addHandler(conn_sock, handler);}
5. 完整的客户端处理逻辑
5.1 客户端事件处理器
cpp浅色版本class ClientHandler : public EventHandler {private: int sock_; bool isClosed_ = false;public: ClientHandler(int sock) : sock_(sock) {} void handleRead() override { char buffer[1024]; ssize_t bytes_read = read(sock_, buffer, sizeof(buffer) - 1); if (bytes_read <= 0) { closeConnection(); return; } buffer[bytes_read] = '\0'; // Null terminate the buffer std::cout << "Received: " << buffer << std::endl; // 回应客户端 write(sock_, buffer, bytes_read); } void handleWrite() override { // 处理写入逻辑 }private: void closeConnection() { isClosed_ = true; close(sock_); }};
6. 主程序
cpp浅色版本int main() { Reactor reactor; int listen_sock = socket(AF_INET, SOCK_STREAM, 0); // 创建 socket if (listen_sock == -1) { std::cerr << "Failed to create socket." << std::endl; return -1; } struct sockaddr_in serv_addr; serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); serv_addr.sin_port = htons(8080); // 设置监听端口 if (bind(listen_sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) == -1) { std::cerr << "Failed to bind socket." << std::endl; return -1; } if (listen(listen_sock, 5) == -1) { std::cerr << "Failed to listen on socket." << std::endl; return -1; } // 将监听 socket 添加到 epoll 实例中 struct epoll_event ev; ev.events = EPOLLIN; // 监听读事件 ev.data.fd = listen_sock; if (epoll_ctl(reactor.getEpollFd(), EPOLL_CTL_ADD, listen_sock, &ev) == -1) { std::cerr << "Failed to add socket to epoll." << std::endl; return -1; } reactor.loop(); return 0;}
7. 测试与优化
- 单元测试:编写单元测试来验证各个模块的功能。
- 压力测试:使用工具如 ab 或 siege 进行压力测试,评估系统的性能极限。
- 性能分析:使用 perf、gprof 等工具分析性能瓶颈,进行针对性优化。
通过上述步骤,你可以构建一个支持百万并发连接的 Reactor 模型服务器。这个框架可以根据具体的应用场景进一步扩展和完善。如果你有特定的需求或者想深入了解某一部分,请随时提问。