如何开发高效服务(C++ )
在 C++ 开发高效服务器时,常用的开发模式和设计模式能够帮助你构建高效、可扩展和可维护的服务器。以下是一些常见的模式和设计模式:
1. 并发和并行编程模型
1.1 Reactor 模式
Reactor 模式是一种事件驱动设计模式,广泛用于高性能服务器编程。它使用事件分离机制和事件处理器来管理多路 I/O 事件。典型实现包括使用 select、poll 或 epoll 等系统调用。
核心组件:
- Event Demultiplexer:如
select或epoll,用于等待事件。 - 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)
单例模式确保一个类只有一个实例,并提供一个全局访问点。服务器中的配置管理器或日志管理器通常使用单例模式。
class Singleton {
public:static Singleton& getInstance() {static Singleton instance;return instance;}private:Singleton() {}Singleton(const Singleton&) = delete;Singleton& operator=(const Singleton&) = delete;
};
2.2 工厂模式(Factory)
工厂模式用于创建对象,而不必指定具体类。它使得代码更加灵活和可扩展。服务器中常用于创建各种处理器或服务。
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;}
};
2.3 观察者模式(Observer)
观察者模式定义对象间的一对多依赖关系,当一个对象改变状态时,所有依赖它的对象都会收到通知并自动更新。常用于事件系统和通知机制。
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();}}
};
2.4 策略模式(Strategy)
策略模式定义了一系列算法,并将每个算法封装起来,使它们可以互换。服务器中常用于动态选择处理算法或策略。
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();}}
};
3. 多线程编程模型
3.1 线程池(Thread Pool)
线程池模式预先创建一组线程来处理任务,从而避免了频繁创建和销毁线程的开销。它可以提高服务器的性能和响应速度。
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();}}
};
3.2 任务队列(Task Queue)
任务队列是一种将任务排队等待处理的机制。可以与线程池结合使用,实现任务的并行处理。
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;}
};
4. 网络通信模式
4.1 多路复用(Multiplexing)
使用 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)
代码实现
1. 线程池类 (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();}
}
2. 客户端处理类 (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);
}
3. 服务器类 (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();});
}
4. 主程序入口 (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 进行多路复用,并使用线程池来处理客户端请求,确保服务器的高性能和高并发处理能力。
相关文章:
如何开发高效服务(C++ )
在 C 开发高效服务器时,常用的开发模式和设计模式能够帮助你构建高效、可扩展和可维护的服务器。以下是一些常见的模式和设计模式: 1. 并发和并行编程模型 1.1 Reactor 模式 Reactor 模式是一种事件驱动设计模式,广泛用于高性能服务器编程…...
STM32实现多级菜单界面显示
1、main函数中,while循环之前 MenuStruct menu[30] //定义多级菜单结构体数组{{0,0,0,1,show0}, //第一个元素表示索引号,第二个元素表示该按键按下后要返回的界面,第三个元素表示该按键按下后要切换的菜单条目界面,第四个元素…...
Qt事件处理和传递流程
事件系统的概述 事件的类型 Qt 支持多种事件类型,每种类型代表不同的用户交互或系统事件。常见的事件类型包括: 输入事件:如鼠标事件(QMouseEvent)、键盘事件(QKeyEvent)。窗口事件ÿ…...
基于STM32移植U8g2图形库——OLED显示(HAL库)
文章目录 一、U8g2简介1、特点2、U8g2的使用步骤 二、I2C相关介绍1、I2C的基本原理2、I2C的时序协议 三、OLED屏的工作原理四、汉字点阵显示原理五、建立STM32CubeMX工程六、U8g2移植1、U8g2源码2、移植过程 七、代码编写1、参考博主实现的U82G的demo例程(1…...
C语言概述与历史
引言 C语言是一门历史悠久且影响深远的编程语言。它不仅为后继的许多编程语言奠定了基础,同时因其高效性和灵活性在系统编程和嵌入式开发领域得到了广泛应用。本篇文章将全面介绍C语言的起源与发展、设计目标与理念,以及C语言的标准演化历程,…...
钉钉Stream模式推送程序环境部署
python3.10版本需要openssl1.1.1及以上版本 参考链接:https://blog.csdn.net/weixin_42806458/article/details/110678710 wget https://www.openssl.org/source/openssl-1.1.1q.tar.gz unzip openssl-1.1.1q.tar.gz cd openssl-1.1.1q ./config --prefix/usr/loc…...
c# 二维图形绘制实践
1.等边三角形 1.1 概述 1.2 代码 using System; using System.Drawing; using System.Windows.Forms;public partial class TriangleForm : Form {public TriangleForm(){//InitializeComponent();// 确保窗体大小足够大,以容纳三角形 this.ClientSize new Siz…...
Nvidia TensorRT系列01-TensorRT的功能1
Nvidia TensorRT系列01-TensorRT的功能1 B站:肆十二-的个人空间-肆十二-个人主页-哔哩哔哩视频 (bilibili.com) 博客:肆十二-CSDN博客 问答:(10 封私信 / 72 条消息) 肆十二 - 知乎 (zhihu.com) C和Python API TensorRT的API同时支持C和Pyth…...
Vatee万腾平台:创新科技,助力企业腾飞
在全球化竞争日益激烈的今天,企业如何借助科技力量实现转型升级,已成为摆在众多企业家面前的重大课题。Vatee万腾平台凭借其卓越的创新科技和专业的服务能力,成为众多企业实现腾飞的得力助手。 一、创新科技,引领企业前行 Vatee万…...
搭建k8s集群报错unknown command “\u00a0“ for “kubeadm init“
搭建k8s报错unknown command “\u00a0” for “kubeadm init” 网上搜了一下,是因为复制过来的命令前面包含了空格,将复制的命令放到idea可以清楚看到几个命令前面有空格,删除掉就好了,记录一下...
【数据结构】三路快速排序
1. 简介 传统快速排序用的是双路快速排序,即将大于基准值的部分放到基准值右侧,小于基准值的部分放到基准值左侧,但是这种算法面对过多的重复数据的数组,时间复杂度会增多,于是就有了三路快速排序的思想,其…...
中国菜刀,蚁剑,哥斯拉,冰蝎的流量特征区别
中国菜刀、蚁剑、哥斯拉、冰蝎这四种Webshell连接工具的流量特征各有区别,以下是它们之间的主要差异: 中国菜刀(CaiDao) 流量特征: 请求包: UA头可能伪装为百度、火狐等浏览器的User-Agent。请求体中存在…...
华为OD刷题C卷 - 每日刷题32(执行任务赚积分,计算三叉搜索树的高度)
1、(执行任务赚积分): 这段代码是解决“执行任务赚积分”的问题。它提供了一个Java类Main,其中包含main方法和getResult方法,用于计算在有限的时间内,处理任务可以获得的最多积分。 main方法首先读取任务…...
QT系列教程(11) TextEdit实现Qt 文本高亮
文本高亮 对于textedit里录入的部分单词我们可以实现高亮,实现高亮主要依赖于QSyntaxHighlighter。 我们先创建一个Qt Application类,类名MainWindow, 然后新增一个C类,类名为MySyntaxHighlighter。 #ifndef MYSYNTAXHIGHLIGHTER_H #define …...
蓝队-溯源技巧
溯源技巧 大致思想 通常情况下,接到溯源任务时,获得的信息如下 攻击时间 攻击 IP 预警平台 攻击类型 恶意文件 受攻击域名/IP其中攻击 IP、攻击类型、恶意文件、攻击详情是溯源入手的点。 通过攻击类型分析攻击详情的请求包,看有没有攻击者…...
【5】JDK、JRE和JVM的区别与联系
JDK、JRE和JVM的区别与联系 Java是一种广泛使用的编程语言,它的跨平台特性得益于Java虚拟机(JVM)。然而,在Java的世界里,JDK、JRE和JVM这三个术语常常让人感到困惑。本文将阐述它们各自的功能,以及它们是如…...
【DevOps】Logstash详解:高效日志管理与分析工具
在现代软件开发和运维过程中,日志管理与分析是至关重要的环节。日志可以帮助我们追踪系统行为、诊断问题、优化性能以及确保安全合规。Logstash,作为ELK Stack(Elasticsearch、Logstash、Kibana)的核心组件之一,是一个…...
Vue3 之 Pinia 核心概念(八)
核心概念 State:这是你的应用程序的状态,是一个响应式的对象。 Getters:类似于 Vuex 中的 getters,它们是基于 state 的计算属性。 Actions:类似于 Vuex 中的 mutations 和 actions,它们用于改变 state。但…...
【办公类-04-03】华为助手导出照片视频分类(根据图片、视频的文件名日期分类导出)
背景需求: 用华为手机助手导出的照片视频,只能将jpg照片(exifread读取图片的exif拍摄日期,Png、JPEG、mp4都无法识别到exif信息) 【办公类-04-02】华为助手导出照片(jpg)读取拍摄时间分类导出…...
TVBOX 最新版下载+视频源教程
下载链接 wx 搜索 Geek 前端 发送电视资源进行获取 操作教程...
Debian系统简介
目录 Debian系统介绍 Debian版本介绍 Debian软件源介绍 软件包管理工具dpkg dpkg核心指令详解 安装软件包 卸载软件包 查询软件包状态 验证软件包完整性 手动处理依赖关系 dpkg vs apt Debian系统介绍 Debian 和 Ubuntu 都是基于 Debian内核 的 Linux 发行版ÿ…...
大型活动交通拥堵治理的视觉算法应用
大型活动下智慧交通的视觉分析应用 一、背景与挑战 大型活动(如演唱会、马拉松赛事、高考中考等)期间,城市交通面临瞬时人流车流激增、传统摄像头模糊、交通拥堵识别滞后等问题。以演唱会为例,暖城商圈曾因观众集中离场导致周边…...
Java如何权衡是使用无序的数组还是有序的数组
在 Java 中,选择有序数组还是无序数组取决于具体场景的性能需求与操作特点。以下是关键权衡因素及决策指南: ⚖️ 核心权衡维度 维度有序数组无序数组查询性能二分查找 O(log n) ✅线性扫描 O(n) ❌插入/删除需移位维护顺序 O(n) ❌直接操作尾部 O(1) ✅内存开销与无序数组相…...
【SpringBoot】100、SpringBoot中使用自定义注解+AOP实现参数自动解密
在实际项目中,用户注册、登录、修改密码等操作,都涉及到参数传输安全问题。所以我们需要在前端对账户、密码等敏感信息加密传输,在后端接收到数据后能自动解密。 1、引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId...
JVM垃圾回收机制全解析
Java虚拟机(JVM)中的垃圾收集器(Garbage Collector,简称GC)是用于自动管理内存的机制。它负责识别和清除不再被程序使用的对象,从而释放内存空间,避免内存泄漏和内存溢出等问题。垃圾收集器在Ja…...
linux arm系统烧录
1、打开瑞芯微程序 2、按住linux arm 的 recover按键 插入电源 3、当瑞芯微检测到有设备 4、松开recover按键 5、选择升级固件 6、点击固件选择本地刷机的linux arm 镜像 7、点击升级 (忘了有没有这步了 估计有) 刷机程序 和 镜像 就不提供了。要刷的时…...
CocosCreator 之 JavaScript/TypeScript和Java的相互交互
引擎版本: 3.8.1 语言: JavaScript/TypeScript、C、Java 环境:Window 参考:Java原生反射机制 您好,我是鹤九日! 回顾 在上篇文章中:CocosCreator Android项目接入UnityAds 广告SDK。 我们简单讲…...
零基础设计模式——行为型模式 - 责任链模式
第四部分:行为型模式 - 责任链模式 (Chain of Responsibility Pattern) 欢迎来到行为型模式的学习!行为型模式关注对象之间的职责分配、算法封装和对象间的交互。我们将学习的第一个行为型模式是责任链模式。 核心思想:使多个对象都有机会处…...
精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南
精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南 在数字化营销时代,邮件列表效度、用户参与度和网站性能等指标往往决定着创业公司的增长成败。今天,我们将深入解析邮件打开率、网站可用性、页面参与时…...
laravel8+vue3.0+element-plus搭建方法
创建 laravel8 项目 composer create-project --prefer-dist laravel/laravel laravel8 8.* 安装 laravel/ui composer require laravel/ui 修改 package.json 文件 "devDependencies": {"vue/compiler-sfc": "^3.0.7","axios": …...
