赞
踩
在 C++ 开发高效服务器时,常用的开发模式和设计模式能够帮助你构建高效、可扩展和可维护的服务器。以下是一些常见的模式和设计模式:
Reactor 模式是一种事件驱动设计模式,广泛用于高性能服务器编程。它使用事件分离机制和事件处理器来管理多路 I/O 事件。典型实现包括使用 select
、poll
或 epoll
等系统调用。
核心组件:
select
或 epoll
,用于等待事件。Proactor 模式是另一种事件驱动设计模式,区别于 Reactor 模式的是它使用异步 I/O 操作。I/O 操作在后台完成,完成后通知应用程序。
核心组件:
单例模式确保一个类只有一个实例,并提供一个全局访问点。服务器中的配置管理器或日志管理器通常使用单例模式。
- class Singleton {
- public:
- static Singleton& getInstance() {
- static Singleton instance;
- return instance;
- }
-
- private:
- Singleton() {}
- Singleton(const Singleton&) = delete;
- Singleton& operator=(const Singleton&) = delete;
- };
工厂模式用于创建对象,而不必指定具体类。它使得代码更加灵活和可扩展。服务器中常用于创建各种处理器或服务。
- class AbstractProduct {
- public:
- virtual void doSomething() = 0;
- virtual ~AbstractProduct() {}
- };
-
- class ConcreteProductA : public AbstractProduct {
- public:
- void doSomething() override {
- // Implementation for ConcreteProductA
- }
- };
-
- class ConcreteProductB : public AbstractProduct {
- public:
- void doSomething() override {
- // Implementation for ConcreteProductB
- }
- };
-
- class Factory {
- public:
- static std::unique_ptr<AbstractProduct> createProduct(char type) {
- if (type == 'A') return std::make_unique<ConcreteProductA>();
- if (type == 'B') return std::make_unique<ConcreteProductB>();
- return nullptr;
- }
- };

观察者模式定义对象间的一对多依赖关系,当一个对象改变状态时,所有依赖它的对象都会收到通知并自动更新。常用于事件系统和通知机制。
- class Observer {
- public:
- virtual void update() = 0;
- };
-
- class Subject {
- std::vector<std::shared_ptr<Observer>> observers;
-
- public:
- void attach(const std::shared_ptr<Observer>& observer) {
- observers.push_back(observer);
- }
-
- void notify() {
- for (const auto& observer : observers) {
- observer->update();
- }
- }
- };

策略模式定义了一系列算法,并将每个算法封装起来,使它们可以互换。服务器中常用于动态选择处理算法或策略。
- class Strategy {
- public:
- virtual void execute() = 0;
- };
-
- class ConcreteStrategyA : public Strategy {
- public:
- void execute() override {
- // Implementation of strategy A
- }
- };
-
- class ConcreteStrategyB : public Strategy {
- public:
- void execute() override {
- // Implementation of strategy B
- }
- };
-
- class Context {
- std::unique_ptr<Strategy> strategy;
-
- public:
- void setStrategy(std::unique_ptr<Strategy> newStrategy) {
- strategy = std::move(newStrategy);
- }
-
- void executeStrategy() {
- if (strategy) {
- strategy->execute();
- }
- }
- };

线程池模式预先创建一组线程来处理任务,从而避免了频繁创建和销毁线程的开销。它可以提高服务器的性能和响应速度。
- class ThreadPool {
- std::vector<std::thread> workers;
- std::queue<std::function<void()>> tasks;
- std::mutex queueMutex;
- std::condition_variable condition;
- bool stop;
-
- public:
- ThreadPool(size_t threads) : stop(false) {
- for (size_t i = 0; i < threads; ++i) {
- workers.emplace_back([this] {
- while (true) {
- std::function<void()> task;
- {
- std::unique_lock<std::mutex> lock(this->queueMutex);
- this->condition.wait(lock, [this] {
- return this->stop || !this->tasks.empty();
- });
- if (this->stop && this->tasks.empty()) return;
- task = std::move(this->tasks.front());
- this->tasks.pop();
- }
- task();
- }
- });
- }
- }
-
- template<class F>
- void enqueue(F&& f) {
- {
- std::unique_lock<std::mutex> lock(queueMutex);
- tasks.emplace(std::forward<F>(f));
- }
- condition.notify_one();
- }
-
- ~ThreadPool() {
- {
- std::unique_lock<std::mutex> lock(queueMutex);
- stop = true;
- }
- condition.notify_all();
- for (std::thread &worker : workers) {
- worker.join();
- }
- }
- };

任务队列是一种将任务排队等待处理的机制。可以与线程池结合使用,实现任务的并行处理。
- class TaskQueue {
- std::queue<std::function<void()>> tasks;
- std::mutex queueMutex;
-
- public:
- void pushTask(std::function<void()> task) {
- std::lock_guard<std::mutex> lock(queueMutex);
- tasks.push(std::move(task));
- }
-
- std::function<void()> popTask() {
- std::lock_guard<std::mutex> lock(queueMutex);
- if (tasks.empty()) return nullptr;
- auto task = tasks.front();
- tasks.pop();
- return task;
- }
- };

使用 select
、poll
或 epoll
实现多路复用,允许单个线程处理多个网络连接。
- #include <sys/epoll.h>
-
- int epoll_fd = epoll_create1(0);
- struct epoll_event event;
- event.events = EPOLLIN;
- event.data.fd = listen_fd;
- epoll_ctl(epoll_fd, EPOLL_CTL_ADD, listen_fd, &event);
-
- while (true) {
- struct epoll_event events[MAX_EVENTS];
- int nfds = epoll_wait(epoll_fd, events, MAX_EVENTS, -1);
- for (int n = 0; n < nfds; ++n) {
- if (events[n].data.fd == listen_fd) {
- int conn_fd = accept(listen_fd, (struct sockaddr *) &client_addr, &client_len);
- event.data.fd = conn_fd;
- epoll_ctl(epoll_fd, EPOLL_CTL_ADD, conn_fd, &event);
- } else {
- // Handle I/O for events[n].data.fd
- }
- }
- }

使用上述开发模式和设计模式,可以构建高效的 C++ 服务器。选择适合的模式和设计模式可以提高代码的可维护性、可扩展性和性能。在实际开发中,可以根据需求组合使用这些模式,构建出高效可靠的服务器应用。
以下是一个基于上述开发模式和设计模式的高效 C++ 服务器的示例。该服务器使用了 Reactor
模式、线程池
和其他一些设计模式。
我们将项目组织成以下几个部分:
main.cpp
)Server
)ClientHandler
)ThreadPool
)ThreadPool
)我们将先定义一个简单的线程池,用于处理客户端请求。
- // ThreadPool.h
- #ifndef THREADPOOL_H
- #define THREADPOOL_H
-
- #include <vector>
- #include <queue>
- #include <thread>
- #include <mutex>
- #include <condition_variable>
- #include <functional>
-
- class ThreadPool {
- public:
- ThreadPool(size_t numThreads);
- ~ThreadPool();
-
- void enqueue(std::function<void()> task);
-
- private:
- std::vector<std::thread> workers;
- std::queue<std::function<void()>> tasks;
- std::mutex queueMutex;
- std::condition_variable condition;
- bool stop;
-
- void workerThread();
- };
-
- #endif // THREADPOOL_H
-
- // ThreadPool.cpp
- #include "ThreadPool.h"
-
- ThreadPool::ThreadPool(size_t numThreads) : stop(false) {
- for (size_t i = 0; i < numThreads; ++i) {
- workers.emplace_back(&ThreadPool::workerThread, this);
- }
- }
-
- ThreadPool::~ThreadPool() {
- {
- std::unique_lock<std::mutex> lock(queueMutex);
- stop = true;
- }
- condition.notify_all();
- for (std::thread &worker : workers) {
- worker.join();
- }
- }
-
- void ThreadPool::enqueue(std::function<void()> task) {
- {
- std::unique_lock<std::mutex> lock(queueMutex);
- tasks.emplace(std::move(task));
- }
- condition.notify_one();
- }
-
- void ThreadPool::workerThread() {
- while (true) {
- std::function<void()> task;
- {
- std::unique_lock<std::mutex> lock(queueMutex);
- condition.wait(lock, [this] { return stop || !tasks.empty(); });
- if (stop && tasks.empty()) {
- return;
- }
- task = std::move(tasks.front());
- tasks.pop();
- }
- task();
- }
- }

ClientHandler
)处理客户端的连接和请求。
- // ClientHandler.h
- #ifndef CLIENTHANDLER_H
- #define CLIENTHANDLER_H
-
- #include <unistd.h>
- #include <iostream>
-
- class ClientHandler {
- public:
- ClientHandler(int clientSocket);
- void handle();
-
- private:
- int clientSocket;
- };
-
- #endif // CLIENTHANDLER_H
-
- // ClientHandler.cpp
- #include "ClientHandler.h"
-
- ClientHandler::ClientHandler(int clientSocket) : clientSocket(clientSocket) {}
-
- void ClientHandler::handle() {
- char buffer[1024];
- ssize_t bytesRead;
- while ((bytesRead = read(clientSocket, buffer, sizeof(buffer))) > 0) {
- std::cout << "Received: " << std::string(buffer, bytesRead) << std::endl;
- write(clientSocket, buffer, bytesRead); // Echo back to client
- }
- close(clientSocket);
- }

Server
)服务器类使用 epoll
进行多路复用,并利用线程池处理客户端请求。
- // Server.h
- #ifndef SERVER_H
- #define SERVER_H
-
- #include <netinet/in.h>
- #include <sys/epoll.h>
- #include <vector>
- #include "ThreadPool.h"
- #include "ClientHandler.h"
-
- class Server {
- public:
- Server(int port, size_t numThreads);
- ~Server();
- void run();
-
- private:
- int serverSocket;
- int epollFd;
- ThreadPool threadPool;
-
- void acceptConnection();
- void handleClient(int clientSocket);
-
- static const int MAX_EVENTS = 10;
- };
-
- #endif // SERVER_H
-
- // Server.cpp
- #include "Server.h"
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <unistd.h>
- #include <fcntl.h>
- #include <cstring>
- #include <iostream>
-
- Server::Server(int port, size_t numThreads) : threadPool(numThreads) {
- serverSocket = socket(AF_INET, SOCK_STREAM, 0);
- if (serverSocket == -1) {
- throw std::runtime_error("Failed to create socket");
- }
-
- int opt = 1;
- setsockopt(serverSocket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
-
- sockaddr_in serverAddr;
- std::memset(&serverAddr, 0, sizeof(serverAddr));
- serverAddr.sin_family = AF_INET;
- serverAddr.sin_addr.s_addr = INADDR_ANY;
- serverAddr.sin_port = htons(port);
-
- if (bind(serverSocket, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) == -1) {
- throw std::runtime_error("Failed to bind socket");
- }
-
- if (listen(serverSocket, SOMAXCONN) == -1) {
- throw std::runtime_error("Failed to listen on socket");
- }
-
- epollFd = epoll_create1(0);
- if (epollFd == -1) {
- throw std::runtime_error("Failed to create epoll file descriptor");
- }
-
- epoll_event event;
- event.events = EPOLLIN;
- event.data.fd = serverSocket;
-
- if (epoll_ctl(epollFd, EPOLL_CTL_ADD, serverSocket, &event) == -1) {
- throw std::runtime_error("Failed to add server socket to epoll");
- }
- }
-
- Server::~Server() {
- close(serverSocket);
- close(epollFd);
- }
-
- void Server::run() {
- epoll_event events[MAX_EVENTS];
-
- while (true) {
- int numEvents = epoll_wait(epollFd, events, MAX_EVENTS, -1);
- if (numEvents == -1) {
- throw std::runtime_error("Error during epoll wait");
- }
-
- for (int i = 0; i < numEvents; ++i) {
- if (events[i].data.fd == serverSocket) {
- acceptConnection();
- } else {
- handleClient(events[i].data.fd);
- }
- }
- }
- }
-
- void Server::acceptConnection() {
- int clientSocket = accept(serverSocket, nullptr, nullptr);
- if (clientSocket == -1) {
- std::cerr << "Failed to accept client connection" << std::endl;
- return;
- }
-
- epoll_event event;
- event.events = EPOLLIN | EPOLLET;
- event.data.fd = clientSocket;
-
- if (epoll_ctl(epollFd, EPOLL_CTL_ADD, clientSocket, &event) == -1) {
- std::cerr << "Failed to add client socket to epoll" << std::endl;
- close(clientSocket);
- }
- }
-
- void Server::handleClient(int clientSocket) {
- threadPool.enqueue([clientSocket]() {
- ClientHandler handler(clientSocket);
- handler.handle();
- });
- }

main.cpp
)- // main.cpp
- #include "Server.h"
-
- int main() {
- try {
- Server server(8080, 4); // 端口 8080,4 个线程
- server.run();
- } catch (const std::exception &e) {
- std::cerr << "Error: " << e.what() << std::endl;
- return 1;
- }
-
- return 0;
- }
ThreadPool
类,预先创建线程来处理任务,避免频繁创建和销毁线程的开销。ClientHandler
类用于处理客户端连接,读取客户端数据并将数据回传。Server
类使用 epoll
实现多路复用,监听新连接并将客户端请求交给线程池处理。通过以上代码,我们创建了一个高效的 C++ 服务器,它利用 epoll
进行多路复用,并使用线程池来处理客户端请求,确保服务器的高性能和高并发处理能力。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。