当前位置:   article > 正文

如何开发高效服务(C++ )

如何开发高效服务(C++ )

在 C++ 开发高效服务器时,常用的开发模式和设计模式能够帮助你构建高效、可扩展和可维护的服务器。以下是一些常见的模式和设计模式:

1. 并发和并行编程模型

1.1 Reactor 模式

Reactor 模式是一种事件驱动设计模式,广泛用于高性能服务器编程。它使用事件分离机制和事件处理器来管理多路 I/O 事件。典型实现包括使用 selectpollepoll 等系统调用。

核心组件:

  • Event Demultiplexer:如 selectepoll,用于等待事件。
  • Event Handler:处理特定事件的回调函数。
  • Synchronous Event De-multiplexer:同步事件分离器,负责监听 I/O 事件。
1.2 Proactor 模式

Proactor 模式是另一种事件驱动设计模式,区别于 Reactor 模式的是它使用异步 I/O 操作。I/O 操作在后台完成,完成后通知应用程序。

核心组件:

  • Asynchronous Operation Processor:执行异步 I/O 操作。
  • Completion Handler:异步操作完成后的回调函数。

2. 设计模式

2.1 单例模式(Singleton)

单例模式确保一个类只有一个实例,并提供一个全局访问点。服务器中的配置管理器或日志管理器通常使用单例模式。

  1. class Singleton {
  2. public:
  3. static Singleton& getInstance() {
  4. static Singleton instance;
  5. return instance;
  6. }
  7. private:
  8. Singleton() {}
  9. Singleton(const Singleton&) = delete;
  10. Singleton& operator=(const Singleton&) = delete;
  11. };
2.2 工厂模式(Factory)

工厂模式用于创建对象,而不必指定具体类。它使得代码更加灵活和可扩展。服务器中常用于创建各种处理器或服务。

  1. class AbstractProduct {
  2. public:
  3. virtual void doSomething() = 0;
  4. virtual ~AbstractProduct() {}
  5. };
  6. class ConcreteProductA : public AbstractProduct {
  7. public:
  8. void doSomething() override {
  9. // Implementation for ConcreteProductA
  10. }
  11. };
  12. class ConcreteProductB : public AbstractProduct {
  13. public:
  14. void doSomething() override {
  15. // Implementation for ConcreteProductB
  16. }
  17. };
  18. class Factory {
  19. public:
  20. static std::unique_ptr<AbstractProduct> createProduct(char type) {
  21. if (type == 'A') return std::make_unique<ConcreteProductA>();
  22. if (type == 'B') return std::make_unique<ConcreteProductB>();
  23. return nullptr;
  24. }
  25. };
2.3 观察者模式(Observer)

观察者模式定义对象间的一对多依赖关系,当一个对象改变状态时,所有依赖它的对象都会收到通知并自动更新。常用于事件系统和通知机制。

  1. class Observer {
  2. public:
  3. virtual void update() = 0;
  4. };
  5. class Subject {
  6. std::vector<std::shared_ptr<Observer>> observers;
  7. public:
  8. void attach(const std::shared_ptr<Observer>& observer) {
  9. observers.push_back(observer);
  10. }
  11. void notify() {
  12. for (const auto& observer : observers) {
  13. observer->update();
  14. }
  15. }
  16. };
2.4 策略模式(Strategy)

策略模式定义了一系列算法,并将每个算法封装起来,使它们可以互换。服务器中常用于动态选择处理算法或策略。

  1. class Strategy {
  2. public:
  3. virtual void execute() = 0;
  4. };
  5. class ConcreteStrategyA : public Strategy {
  6. public:
  7. void execute() override {
  8. // Implementation of strategy A
  9. }
  10. };
  11. class ConcreteStrategyB : public Strategy {
  12. public:
  13. void execute() override {
  14. // Implementation of strategy B
  15. }
  16. };
  17. class Context {
  18. std::unique_ptr<Strategy> strategy;
  19. public:
  20. void setStrategy(std::unique_ptr<Strategy> newStrategy) {
  21. strategy = std::move(newStrategy);
  22. }
  23. void executeStrategy() {
  24. if (strategy) {
  25. strategy->execute();
  26. }
  27. }
  28. };

3. 多线程编程模型

3.1 线程池(Thread Pool)

线程池模式预先创建一组线程来处理任务,从而避免了频繁创建和销毁线程的开销。它可以提高服务器的性能和响应速度。

  1. class ThreadPool {
  2. std::vector<std::thread> workers;
  3. std::queue<std::function<void()>> tasks;
  4. std::mutex queueMutex;
  5. std::condition_variable condition;
  6. bool stop;
  7. public:
  8. ThreadPool(size_t threads) : stop(false) {
  9. for (size_t i = 0; i < threads; ++i) {
  10. workers.emplace_back([this] {
  11. while (true) {
  12. std::function<void()> task;
  13. {
  14. std::unique_lock<std::mutex> lock(this->queueMutex);
  15. this->condition.wait(lock, [this] {
  16. return this->stop || !this->tasks.empty();
  17. });
  18. if (this->stop && this->tasks.empty()) return;
  19. task = std::move(this->tasks.front());
  20. this->tasks.pop();
  21. }
  22. task();
  23. }
  24. });
  25. }
  26. }
  27. template<class F>
  28. void enqueue(F&& f) {
  29. {
  30. std::unique_lock<std::mutex> lock(queueMutex);
  31. tasks.emplace(std::forward<F>(f));
  32. }
  33. condition.notify_one();
  34. }
  35. ~ThreadPool() {
  36. {
  37. std::unique_lock<std::mutex> lock(queueMutex);
  38. stop = true;
  39. }
  40. condition.notify_all();
  41. for (std::thread &worker : workers) {
  42. worker.join();
  43. }
  44. }
  45. };
3.2 任务队列(Task Queue)

任务队列是一种将任务排队等待处理的机制。可以与线程池结合使用,实现任务的并行处理。

  1. class TaskQueue {
  2. std::queue<std::function<void()>> tasks;
  3. std::mutex queueMutex;
  4. public:
  5. void pushTask(std::function<void()> task) {
  6. std::lock_guard<std::mutex> lock(queueMutex);
  7. tasks.push(std::move(task));
  8. }
  9. std::function<void()> popTask() {
  10. std::lock_guard<std::mutex> lock(queueMutex);
  11. if (tasks.empty()) return nullptr;
  12. auto task = tasks.front();
  13. tasks.pop();
  14. return task;
  15. }
  16. };

4. 网络通信模式

4.1 多路复用(Multiplexing)

使用 selectpollepoll 实现多路复用,允许单个线程处理多个网络连接。

  1. #include <sys/epoll.h>
  2. int epoll_fd = epoll_create1(0);
  3. struct epoll_event event;
  4. event.events = EPOLLIN;
  5. event.data.fd = listen_fd;
  6. epoll_ctl(epoll_fd, EPOLL_CTL_ADD, listen_fd, &event);
  7. while (true) {
  8. struct epoll_event events[MAX_EVENTS];
  9. int nfds = epoll_wait(epoll_fd, events, MAX_EVENTS, -1);
  10. for (int n = 0; n < nfds; ++n) {
  11. if (events[n].data.fd == listen_fd) {
  12. int conn_fd = accept(listen_fd, (struct sockaddr *) &client_addr, &client_len);
  13. event.data.fd = conn_fd;
  14. epoll_ctl(epoll_fd, EPOLL_CTL_ADD, conn_fd, &event);
  15. } else {
  16. // Handle I/O for events[n].data.fd
  17. }
  18. }
  19. }

总结

使用上述开发模式和设计模式,可以构建高效的 C++ 服务器。选择适合的模式和设计模式可以提高代码的可维护性、可扩展性和性能。在实际开发中,可以根据需求组合使用这些模式,构建出高效可靠的服务器应用。

实现一个简单的服务器

以下是一个基于上述开发模式和设计模式的高效 C++ 服务器的示例。该服务器使用了 Reactor 模式、线程池 和其他一些设计模式。

项目结构

我们将项目组织成以下几个部分:

  1. 主程序入口 (main.cpp)
  2. 服务器类 (Server)
  3. 客户端处理类 (ClientHandler)
  4. 线程池类 (ThreadPool)

代码实现

1. 线程池类 (ThreadPool)

我们将先定义一个简单的线程池,用于处理客户端请求。

  1. // ThreadPool.h
  2. #ifndef THREADPOOL_H
  3. #define THREADPOOL_H
  4. #include <vector>
  5. #include <queue>
  6. #include <thread>
  7. #include <mutex>
  8. #include <condition_variable>
  9. #include <functional>
  10. class ThreadPool {
  11. public:
  12. ThreadPool(size_t numThreads);
  13. ~ThreadPool();
  14. void enqueue(std::function<void()> task);
  15. private:
  16. std::vector<std::thread> workers;
  17. std::queue<std::function<void()>> tasks;
  18. std::mutex queueMutex;
  19. std::condition_variable condition;
  20. bool stop;
  21. void workerThread();
  22. };
  23. #endif // THREADPOOL_H
  24. // ThreadPool.cpp
  25. #include "ThreadPool.h"
  26. ThreadPool::ThreadPool(size_t numThreads) : stop(false) {
  27. for (size_t i = 0; i < numThreads; ++i) {
  28. workers.emplace_back(&ThreadPool::workerThread, this);
  29. }
  30. }
  31. ThreadPool::~ThreadPool() {
  32. {
  33. std::unique_lock<std::mutex> lock(queueMutex);
  34. stop = true;
  35. }
  36. condition.notify_all();
  37. for (std::thread &worker : workers) {
  38. worker.join();
  39. }
  40. }
  41. void ThreadPool::enqueue(std::function<void()> task) {
  42. {
  43. std::unique_lock<std::mutex> lock(queueMutex);
  44. tasks.emplace(std::move(task));
  45. }
  46. condition.notify_one();
  47. }
  48. void ThreadPool::workerThread() {
  49. while (true) {
  50. std::function<void()> task;
  51. {
  52. std::unique_lock<std::mutex> lock(queueMutex);
  53. condition.wait(lock, [this] { return stop || !tasks.empty(); });
  54. if (stop && tasks.empty()) {
  55. return;
  56. }
  57. task = std::move(tasks.front());
  58. tasks.pop();
  59. }
  60. task();
  61. }
  62. }
2. 客户端处理类 (ClientHandler)

处理客户端的连接和请求。

  1. // ClientHandler.h
  2. #ifndef CLIENTHANDLER_H
  3. #define CLIENTHANDLER_H
  4. #include <unistd.h>
  5. #include <iostream>
  6. class ClientHandler {
  7. public:
  8. ClientHandler(int clientSocket);
  9. void handle();
  10. private:
  11. int clientSocket;
  12. };
  13. #endif // CLIENTHANDLER_H
  14. // ClientHandler.cpp
  15. #include "ClientHandler.h"
  16. ClientHandler::ClientHandler(int clientSocket) : clientSocket(clientSocket) {}
  17. void ClientHandler::handle() {
  18. char buffer[1024];
  19. ssize_t bytesRead;
  20. while ((bytesRead = read(clientSocket, buffer, sizeof(buffer))) > 0) {
  21. std::cout << "Received: " << std::string(buffer, bytesRead) << std::endl;
  22. write(clientSocket, buffer, bytesRead); // Echo back to client
  23. }
  24. close(clientSocket);
  25. }
3. 服务器类 (Server)

服务器类使用 epoll 进行多路复用,并利用线程池处理客户端请求。

  1. // Server.h
  2. #ifndef SERVER_H
  3. #define SERVER_H
  4. #include <netinet/in.h>
  5. #include <sys/epoll.h>
  6. #include <vector>
  7. #include "ThreadPool.h"
  8. #include "ClientHandler.h"
  9. class Server {
  10. public:
  11. Server(int port, size_t numThreads);
  12. ~Server();
  13. void run();
  14. private:
  15. int serverSocket;
  16. int epollFd;
  17. ThreadPool threadPool;
  18. void acceptConnection();
  19. void handleClient(int clientSocket);
  20. static const int MAX_EVENTS = 10;
  21. };
  22. #endif // SERVER_H
  23. // Server.cpp
  24. #include "Server.h"
  25. #include <sys/socket.h>
  26. #include <netinet/in.h>
  27. #include <unistd.h>
  28. #include <fcntl.h>
  29. #include <cstring>
  30. #include <iostream>
  31. Server::Server(int port, size_t numThreads) : threadPool(numThreads) {
  32. serverSocket = socket(AF_INET, SOCK_STREAM, 0);
  33. if (serverSocket == -1) {
  34. throw std::runtime_error("Failed to create socket");
  35. }
  36. int opt = 1;
  37. setsockopt(serverSocket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
  38. sockaddr_in serverAddr;
  39. std::memset(&serverAddr, 0, sizeof(serverAddr));
  40. serverAddr.sin_family = AF_INET;
  41. serverAddr.sin_addr.s_addr = INADDR_ANY;
  42. serverAddr.sin_port = htons(port);
  43. if (bind(serverSocket, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) == -1) {
  44. throw std::runtime_error("Failed to bind socket");
  45. }
  46. if (listen(serverSocket, SOMAXCONN) == -1) {
  47. throw std::runtime_error("Failed to listen on socket");
  48. }
  49. epollFd = epoll_create1(0);
  50. if (epollFd == -1) {
  51. throw std::runtime_error("Failed to create epoll file descriptor");
  52. }
  53. epoll_event event;
  54. event.events = EPOLLIN;
  55. event.data.fd = serverSocket;
  56. if (epoll_ctl(epollFd, EPOLL_CTL_ADD, serverSocket, &event) == -1) {
  57. throw std::runtime_error("Failed to add server socket to epoll");
  58. }
  59. }
  60. Server::~Server() {
  61. close(serverSocket);
  62. close(epollFd);
  63. }
  64. void Server::run() {
  65. epoll_event events[MAX_EVENTS];
  66. while (true) {
  67. int numEvents = epoll_wait(epollFd, events, MAX_EVENTS, -1);
  68. if (numEvents == -1) {
  69. throw std::runtime_error("Error during epoll wait");
  70. }
  71. for (int i = 0; i < numEvents; ++i) {
  72. if (events[i].data.fd == serverSocket) {
  73. acceptConnection();
  74. } else {
  75. handleClient(events[i].data.fd);
  76. }
  77. }
  78. }
  79. }
  80. void Server::acceptConnection() {
  81. int clientSocket = accept(serverSocket, nullptr, nullptr);
  82. if (clientSocket == -1) {
  83. std::cerr << "Failed to accept client connection" << std::endl;
  84. return;
  85. }
  86. epoll_event event;
  87. event.events = EPOLLIN | EPOLLET;
  88. event.data.fd = clientSocket;
  89. if (epoll_ctl(epollFd, EPOLL_CTL_ADD, clientSocket, &event) == -1) {
  90. std::cerr << "Failed to add client socket to epoll" << std::endl;
  91. close(clientSocket);
  92. }
  93. }
  94. void Server::handleClient(int clientSocket) {
  95. threadPool.enqueue([clientSocket]() {
  96. ClientHandler handler(clientSocket);
  97. handler.handle();
  98. });
  99. }
4. 主程序入口 (main.cpp)

启动服务器

  1. // main.cpp
  2. #include "Server.h"
  3. int main() {
  4. try {
  5. Server server(8080, 4); // 端口 80804 个线程
  6. server.run();
  7. } catch (const std::exception &e) {
  8. std::cerr << "Error: " << e.what() << std::endl;
  9. return 1;
  10. }
  11. return 0;
  12. }

说明

  1. 线程池:我们定义了一个 ThreadPool 类,预先创建线程来处理任务,避免频繁创建和销毁线程的开销。
  2. 客户端处理ClientHandler 类用于处理客户端连接,读取客户端数据并将数据回传。
  3. 服务器Server 类使用 epoll 实现多路复用,监听新连接并将客户端请求交给线程池处理。

通过以上代码,我们创建了一个高效的 C++ 服务器,它利用 epoll 进行多路复用,并使用线程池来处理客户端请求,确保服务器的高性能和高并发处理能力。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/羊村懒王/article/detail/729569
推荐阅读
相关标签
  

闽ICP备14008679号