qidao123.com技术社区-IT企服评测·应用市场

标题: C++实现基于Reactor模式的百万级并发服务器 [打印本页]

作者: 老婆出轨    时间: 2025-4-3 04:23
标题: C++实现基于Reactor模式的百万级并发服务器


随着互联网应用的复杂性不绝增加,网络服务的并发处理本领变得越来越紧张。对于一个高并发、高吞吐量的服务器,传统的多线程和多历程模型往往会受到资源斲丧、上下文切换等问题的限制。因此,采用高效的事件驱动模型成为了高性能服务器的计划趋势之一。
Reactor 模式作为一种事件驱动的计划模式,已经被广泛应用于高性能服务器的开发中。本文将详细介绍如何使用 C++ 实现一个基于 Reactor 模式的百万级并发服务器。
1. Reactor 模式简介

Reactor 模式是一种事件驱动模式,旨在处理大量并发的 I/O 事件。在该模式下,事件发生时通过“事件分发器”将事件分发到相应的“事件处理器”进行处理。Reactor 模式具有以下特点:

1.1 Reactor 模式的布局

Reactor 模式的基本布局由以下几个组成部分构成:

2. 高并发服务器的计划挑战

在计划百万级并发的服务器时,紧张面临以下挑战:
2.1 I/O 阻塞与多线程开销

传统的阻塞式 I/O 模型会导致线程处于等待状态,从而浪费大量的体系资源。而使用多线程模型时,线程的频仍切换、上下文切换和线程池的管理也会引发明显的性能开销。
2.2 事件通知机制

如何实时、精确地获取网络事件的发生,并将事件分发给相应的处理器,是高效并发服务器的核心问题。通过 I/O 多路复用,Reactor 模式可以同时监听多个文件描述符,并在相应事件发生时进行处理。
2.3 体系资源斲丧

百万级并发的服务器必要保证资源的高效使用。通过制止为每个连接创建独立的线程,Reactor 模式有用淘汰了体系资源斲丧。
3. C++ 中的 Reactor 模式实现

为了实现一个基于 Reactor 模式的高并发服务器,我们必要使用高效的 I/O 多路复用机制,例如 epoll(在 Linux 环境下)。下面我们将使用 C++ 实现一个简单的 Reactor 模式服务器,该服务器可以或许处理百万级并发请求。
3.1 事件处理器(Handler)

事件处理器负责处理每个客户端的 I/O 操纵。在这个示例中,我们的事件处理器会在吸收到数据时进行处理,并返回一个响应。
  1. #include <iostream>
  2. #include <unistd.h>
  3. #include <cstring>
  4. class EventHandler {
  5. public:
  6.     virtual void handle_read(int fd) = 0;
  7.     virtual void handle_write(int fd) = 0;
  8.     virtual void handle_error(int fd) = 0;
  9. };
  10. class EchoHandler : public EventHandler {
  11. public:
  12.     void handle_read(int fd) override {
  13.         char buffer[1024];
  14.         int bytesRead = read(fd, buffer, sizeof(buffer));
  15.         if (bytesRead > 0) {
  16.             std::cout << "Received data: " << std::string(buffer, bytesRead) << std::endl;
  17.             write(fd, buffer, bytesRead); // Echo back the data
  18.         } else {
  19.             handle_error(fd);
  20.         }
  21.     }
  22.     void handle_write(int fd) override {
  23.         // Handle write events if necessary (usually handled after reading)
  24.     }
  25.     void handle_error(int fd) override {
  26.         close(fd);
  27.         std::cout << "Error or connection closed for fd: " << fd << std::endl;
  28.     }
  29. };
复制代码
3.2 Reactor(事件分发器)

Reactor 是事件分发的核心,负责通过 epoll 监听多个客户端的 I/O 事件,并将事件分发给相应的事件处理器。
  1. #include <sys/epoll.h>
  2. #include <fcntl.h>
  3. #include <unistd.h>
  4. #include <iostream>
  5. #include <vector>
  6. class Reactor {
  7. public:
  8.     Reactor() {
  9.         epoll_fd = epoll_create1(0);
  10.         if (epoll_fd == -1) {
  11.             std::cerr << "Failed to create epoll instance" << std::endl;
  12.             exit(1);
  13.         }
  14.     }
  15.     ~Reactor() {
  16.         close(epoll_fd);
  17.     }
  18.     void register_handler(int fd, EventHandler* handler) {
  19.         struct epoll_event ev;
  20.         ev.events = EPOLLIN | EPOLLOUT | EPOLLET;
  21.         ev.data.fd = fd;
  22.         epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev);
  23.         handlers[fd] = handler;
  24.     }
  25.     void run() {
  26.         const int MAX_EVENTS = 100;
  27.         struct epoll_event events[MAX_EVENTS];
  28.         while (true) {
  29.             int eventCount = epoll_wait(epoll_fd, events, MAX_EVENTS, -1);
  30.             for (int i = 0; i < eventCount; ++i) {
  31.                 int fd = events[i].data.fd;
  32.                 if (events[i].events & EPOLLIN) {
  33.                     handlers[fd]->handle_read(fd);
  34.                 }
  35.                 if (events[i].events & EPOLLOUT) {
  36.                     handlers[fd]->handle_write(fd);
  37.                 }
  38.                 if (events[i].events & (EPOLLERR | EPOLLHUP)) {
  39.                     handlers[fd]->handle_error(fd);
  40.                 }
  41.             }
  42.         }
  43.     }
  44. private:
  45.     int epoll_fd;
  46.     std::unordered_map<int, EventHandler*> handlers;
  47. };
复制代码
3.3 服务端实现

最后,我们必要实现服务器的主程序,负责监听客户端连接、接受连接请求、创建新的事件处理器,并将这些连接注册到 Reactor 中。
  1. #include <sys/socket.h>
  2. #include <netinet/in.h>
  3. #include <arpa/inet.h>
  4. #include <iostream>
  5. #include <fcntl.h>
  6. #define SERVER_PORT 8080
  7. #define SERVER_ADDR "127.0.0.1"
  8. int create_server_socket() {
  9.     int server_fd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0);
  10.     if (server_fd == -1) {
  11.         std::cerr << "Failed to create socket" << std::endl;
  12.         exit(1);
  13.     }
  14.     sockaddr_in server_addr;
  15.     server_addr.sin_family = AF_INET;
  16.     server_addr.sin_port = htons(SERVER_PORT);
  17.     server_addr.sin_addr.s_addr = inet_addr(SERVER_ADDR);
  18.     if (bind(server_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1) {
  19.         std::cerr << "Failed to bind socket" << std::endl;
  20.         exit(1);
  21.     }
  22.     if (listen(server_fd, 100) == -1) {
  23.         std::cerr << "Failed to listen on socket" << std::endl;
  24.         exit(1);
  25.     }
  26.     return server_fd;
  27. }
  28. int main() {
  29.     int server_fd = create_server_socket();
  30.     Reactor reactor;
  31.     EchoHandler handler;
  32.     while (true) {
  33.         sockaddr_in client_addr;
  34.         socklen_t client_len = sizeof(client_addr);
  35.         int client_fd = accept(server_fd, (struct sockaddr*)&client_addr, &client_len);
  36.         if (client_fd != -1) {
  37.             std::cout << "New connection from client" << std::endl;
  38.             reactor.register_handler(client_fd, &handler);
  39.         }
  40.     }
  41.     reactor.run();
  42.     return 0;
  43. }
复制代码
3.4 编译与运行

将上述代码保存为 C++ 源文件(如 server.cpp),并使用以下下令进行编译:
  1. g++ server.cpp -o server -std=c++11 -pthread
复制代码
然后运行服务器:
  1. ./server
复制代码
4. 总结

通过使用 Reactor 模式,我们可以或许构建一个高效的、可以或许支持百万级并发连接的服务器。通过 epoll 等 I/O 多路复用技能,我们制止了传统多线程模型中线程创建和上下文切换的开销,实现了更高效的并发处理本领。Reactor 模式不仅可以或许提高体系的吞吐量,还能有用使用体系资源,是构建高性能服务器的理想选择。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 qidao123.com技术社区-IT企服评测·应用市场 (https://dis.qidao123.com/) Powered by Discuz! X3.4