如何开发高效服务(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 前端 发送电视资源进行获取 操作教程...

2024年了,苹果可以通话录音了
人不走空 🌈个人主页:人不走空 💖系列专栏:算法专题 ⏰诗词歌赋:斯是陋室,惟吾德馨 6月11日凌晨,苹果在WWDC24大会上,密集输出了酝酿多时的AI应用更新。苹果对通话、对话、图…...

书生·浦语大模型实战营第二期作业五
1、开发机创建conda环境: 2、安装第三方库: 3、新建pipeline_transformer.py文件,并运行: 4、运行结果: 5、执行模型: 6、与大模型进行对话: 7、默认占有的显存: 8、--cache-max-en…...

树莓派4B_OpenCv学习笔记9:图片的腐蚀与膨胀
今日继续学习树莓派4B 4G:(Raspberry Pi,简称RPi或RasPi) 本人所用树莓派4B 装载的系统与版本如下: 版本可用命令 (lsb_release -a) 查询: Opencv 版本是4.5.1: 图像的膨胀与腐蚀一般用于灰度图或者二值图,今日便来学习…...

Perplexity AI — 探索网络,发掘知识,沟通思想
体验地址:Perplexity AI (国外网站访问需要梯子) Perplexity AI是一款功能强大的人工智能搜索引擎,其特点和优势主要体现在以下几个方面: 功能: 自然语言搜索:Perplexity AI可以理解用户的自然…...

RPC知识
一、为什么要有RPC: HTTP协议的接口,在接口不多、系统与系统交互较少的情况下,解决信息孤岛初期常使用的一种通信手段;优点就是简单、直接、开发方便,利用现成的HTTP协议进行传输。 但是,如果是一个大型的网…...

【爬虫】requests 结合 BeautifulSoup抓取网页数据
一、BeautifulSoup使用步骤 BeautifulSoup 是一个用于从 HTML 或 XML 文件中提取数据的 Python 库。以下是如何使用 BeautifulSoup 来解析 HTML 并提取信息的基本步骤: 1、安装: 如果你还没有安装 BeautifulSoup,你可以使用 pip 来安装它。…...

安全测试框架 二
使用安全测试框架进行测试,可以遵循以下步骤进行,以确保测试的全面性和系统性: 一、明确测试目标和需求 确定测试的范围和重点,明确要测试的系统或应用的安全性方面的关键点和重要性。根据业务需求和安全标准,制定详…...

安徽京准-NTP网络授时服务器助力助力甘南州公共资源交易
安徽京准-NTP网络授时服务器助力助力甘南州公共资源交易 安徽京准-NTP网络授时服务器助力助力甘南州公共资源交易 2024年5月中旬,我安徽京准科技生产研发的NTP时钟服务器成功投运甘南州公共资源交易中心,为该中心的计算机网络系统及其他各业务子系统提供…...

大数据—什么是大数据?
大数据是指所涉及的资料量规模巨大到无法透过主流软件工具,在合理时间内达到撷取、管理、处理、并整理成为帮助企业经营决策更积极目的的资讯。想要更加全面地了解大数据的概念,可以从以下几个维度进行介绍: 大数据的定义: 基本…...

德克萨斯大学奥斯汀分校自然语言处理硕士课程汉化版(第十一周) - 自然语言处理扩展研究
自然语言处理扩展研究 1. 多语言研究2. 语言锚定3. 伦理问题 1. 多语言研究 多语言(Multilinguality)是NLP的一个重要研究方向,旨在开发能够处理多种语言的模型和算法。由于不同语言在语法、词汇和语义结构上存在差异,这成为一个复杂且具有挑战性的研究…...