粗解JQHttpServer

JQHttpServer是基于Qt开发的轻量级HTTP/HTTPS服务器。

GitHub地址:GitHub - 188080501/JQHttpServer: 基于Qt开发的轻量级HTTP/HTTPS服务器
不愧是大神写的,用起来确实方便。

下面粗略介绍 jqhttpserver.h 的各类的作用,先看源代码:
 

/*This file is part of JQLibraryCopyright: JasonContact email: 188080501@qq.comGNU Lesser General Public License UsageAlternatively, this file may be used under the terms of the GNU LesserGeneral Public License version 2.1 or version 3 as published by the FreeSoftware Foundation and appearing in the file LICENSE.LGPLv21 andLICENSE.LGPLv3 included in the packaging of this file. Please review thefollowing information to ensure the GNU Lesser General Public Licenserequirements will be met: https://www.gnu.org/licenses/lgpl.html andhttp://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
*/#ifndef JQLIBRARY_INCLUDE_JQHTTPSERVER_H_
#define JQLIBRARY_INCLUDE_JQHTTPSERVER_H_#ifndef QT_NETWORK_LIB
#   error("Please add network in pro file")
#endif#ifndef QT_CONCURRENT_LIB
#   error("Please add concurrent in pro file")
#endif// C++ lib import
#include <functional>// Qt lib import
#include <QVector>
#include <QFuture>
#include <QMutex>
#include <QUrl>
#ifndef QT_NO_SSL
#   include <QSslCertificate>
#   include <QSslSocket>
#endif#include "jqdeclare.hpp"class QIODevice;
class QThreadPool;
class QHostAddress;
class QTimer;
class QImage;
class QTcpServer;
class QLocalServer;
class QSslKey;
class QSslConfiguration;namespace JQHttpServer
{class Session: public QObject
{Q_OBJECTQ_DISABLE_COPY( Session )public:Session( const QPointer<QIODevice> &socket );~Session();void setHandleAcceptedCallback(const std::function<void(const QPointer<Session> &)> &callback) { handleAcceptedCallback_ = callback; }QPointer<QIODevice> ioDevice() { return ioDevice_; }QString requestSourceIp() const;QString requestMethod() const;QString requestUrl() const;QString requestCrlf() const;QMap<QString, QString> requestHeader() const;QByteArray requestBody() const;QString requestUrlPath() const;QStringList requestUrlPathSplitToList() const;QMap<QString, QString> requestUrlQuery() const;int replyHttpCode() const;qint64 replyBodySize() const;#ifndef QT_NO_SSLQSslCertificate peerCertificate() const;
#endifvolatile int m_isSafeExit;public slots:void replyText(const QString &replyData, const int &httpStatusCode = 200);void replyRedirects(const QUrl &targetUrl, const int &httpStatusCode = 200);void replyJsonObject(const QJsonObject &jsonObject, const int &httpStatusCode = 200);void replyJsonArray(const QJsonArray &jsonArray, const int &httpStatusCode = 200);void replyFile(const QString &filePath, const int &httpStatusCode = 200);void replyFile(const QString &fileName, const QByteArray &fileData, const int &httpStatusCode = 200);void replyImage(const QImage &image, const QString &format = "PNG", const int &httpStatusCode = 200);void replyImage(const QString &imageFilePath, const int &httpStatusCode = 200);void replyBytes(const QByteArray &bytes, const QString &contentType = "application/octet-stream", const int &httpStatusCode = 200);void replyOptions();private:void inspectionBufferSetup1();void inspectionBufferSetup2();void onBytesWritten(const qint64 &written);void waitWorkingForFinished();private:static QAtomicInt remainSession_;QPointer<QIODevice>                                   ioDevice_;std::function<void( const QPointer<Session> & )>      handleAcceptedCallback_;QSharedPointer<QTimer>                                autoCloseTimer_;QByteArray receiveBuffer_;QString                  requestSourceIp_;QString                  requestMethod_;QString                  requestUrl_;QString                  requestCrlf_;QByteArray               requestBody_;QMap<QString, QString> requestHeader_;bool   headerAcceptedFinished_  = false;bool   contentAcceptedFinished_ = false;qint64 contentLength_           = -1;int        replyHttpCode_ = -1;QByteArray replyBuffer_;qint64     replyBodySize_ = -1;qint64                      waitWrittenByteCount_ = -1;QSharedPointer<QIODevice> replyIoDevice_;
};class AbstractManage: public QObject
{Q_OBJECTQ_DISABLE_COPY( AbstractManage )public:AbstractManage(const int &handleMaxThreadCount);virtual ~AbstractManage();void setMainObject(QObject *obj) { m_mainObj = obj; }QObject* getMainObject() { return m_mainObj; }void setHttpAcceptedCallback(const std::function<void(const QPointer<Session> &session,QObject *mainObj)> &httpAcceptedCallback){httpAcceptedCallback_ = httpAcceptedCallback;}QSharedPointer<QThreadPool> handleThreadPool() { return handleThreadPool_; }QSharedPointer<QThreadPool> serverThreadPool() { return serverThreadPool_; }virtual bool isRunning() = 0;protected Q_SLOTS:bool initialize();void deinitialize();protected:virtual bool onStart() = 0;virtual void onFinish() = 0;bool startServerThread();void stopHandleThread();void stopServerThread();void newSession(const QPointer<Session> &session);void handleAccepted(const QPointer<Session> &session);signals:void readyToClose();//void onRedReady(const QPointer<JQHttpServer::Session> &session);protected:QSharedPointer<QThreadPool> serverThreadPool_;QSharedPointer<QThreadPool> handleThreadPool_;QMutex mutex_;std::function<void(const QPointer<Session> &session,QObject *mainObj)> httpAcceptedCallback_;QSet<Session *> availableSessions_;QObject *m_mainObj;
};class TcpServerManage: public AbstractManage
{Q_OBJECTQ_DISABLE_COPY( TcpServerManage )public:TcpServerManage(const int &handleMaxThreadCount = 2);~TcpServerManage();bool listen( const QHostAddress &address, const quint16 &port );quint16 getListenPort() { return listenPort_; }private:bool isRunning();bool onStart();void onFinish();private:QPointer<QTcpServer> tcpServer_;QHostAddress listenAddress_ = QHostAddress::Any;quint16 listenPort_ = 0;
};#ifndef QT_NO_SSL
class SslServerHelper;class SslServerManage: public AbstractManage
{Q_OBJECTQ_DISABLE_COPY( SslServerManage )public:SslServerManage(const int &handleMaxThreadCount = 2);~SslServerManage();bool listen( const QHostAddress &                                   address,const quint16 &                                        port,const QString &                                        crtFilePath,const QString &                                        keyFilePath,const QList<QPair<QString, QSsl::EncodingFormat>> &caFileList = {},    // [ { filePath, format } ]const QSslSocket::PeerVerifyMode &                     peerVerifyMode = QSslSocket::VerifyNone );quint16 getListenPort() { return listenPort_; }private:bool isRunning();bool onStart();void onFinish();private:QPointer<SslServerHelper> tcpServer_;QHostAddress listenAddress_ = QHostAddress::Any;quint16      listenPort_    = 0;QSharedPointer<QSslConfiguration> sslConfiguration_;
};enum ServiceConfigEnum
{ServiceUnknownConfig,ServiceHttpListenPort,ServiceHttpsListenPort,ServiceProcessor, // QPointer<QObject> or QList<QPointer<QObject>>ServiceUuid,ServiceSslCrtFilePath,ServiceSslKeyFilePath,ServiceSslCAFilePath,ServiceSslPeerVerifyMode,
};class Service: public QObject
{Q_OBJECTQ_DISABLE_COPY( Service )private:enum ReceiveDataType{UnknownReceiveDataType,NoReceiveDataType,VariantListReceiveDataType,VariantMapReceiveDataType,ListVariantMapReceiveDataType,};struct ApiConfig{QPointer<QObject> process;QString             apiMethod;QString             apiName;QString             slotName;ReceiveDataType     receiveDataType = UnknownReceiveDataType;};class Recoder{public:Recoder( const QPointer<JQHttpServer::Session> &session );~Recoder();QPointer<JQHttpServer::Session> session_;QDateTime                         acceptedTime_;QString                           serviceUuid_;QString                           apiName;};protected:Service() = default;public:~Service() = default;static QSharedPointer<Service> createService( const QMap<ServiceConfigEnum, QVariant> &config );void registerProcessor( const QPointer<QObject> &processor );virtual QJsonDocument extractPostJsonData( const QPointer<JQHttpServer::Session> &session );static void reply(const QPointer<JQHttpServer::Session> &session,const QJsonObject &data,const bool &isSucceed = true,const QString &message = { },const int &httpStatusCode = 200 );static void reply(const QPointer<JQHttpServer::Session> &session,const bool &isSucceed = true,const QString &message = { },const int &httpStatusCode = 200 );virtual void httpGetPing( const QPointer<JQHttpServer::Session> &session );virtual void httpGetFaviconIco( const QPointer<JQHttpServer::Session> &session );virtual void httpOptions( const QPointer<JQHttpServer::Session> &session );protected:bool initialize( const QMap<ServiceConfigEnum, QVariant> &config );private:void onSessionAccepted( const QPointer<JQHttpServer::Session> &session );static QString snakeCaseToCamelCase(const QString &source, const bool &firstCharUpper = false);static QList<QVariantMap> variantListToListVariantMap(const QVariantList &source);private:QSharedPointer<JQHttpServer::TcpServerManage> httpServerManage_;QSharedPointer<JQHttpServer::SslServerManage> httpsServerManage_;QString                                     serviceUuid_;QMap<QString, QMap<QString, ApiConfig>> schedules_;    // apiMethod -> apiName -> APIQMap<QString, std::function<void( const QPointer<JQHttpServer::Session> &session )>> schedules2_; // apiPathPrefix -> callbackQPointer<QObject> certificateVerifier_;
};
#endif}#endif//JQLIBRARY_INCLUDE_JQHTTPSERVER_H_

1. Session 类

作用:处理单个 HTTP 请求/响应会话的全生命周期

核心功能

  • 请求解析
    存储 HTTP 请求的元数据(如 requestMethod_requestUrl_requestHeader_ 等),提供接口获取请求的:

    • 客户端 IP (requestSourceIp())

    • 请求方法(GET/POST等)

    • URL 路径和查询参数

    • 请求头和请求体内容

  • 响应生成
    提供多种响应方式:

    • 文本/JSON/二进制数据回复(replyText()/replyJsonObject()/replyBytes()

    • 文件/图片传输(replyFile()/replyImage()

    • 重定向(replyRedirects()

    • 支持设置 HTTP 状态码和自定义 Content-Type

  • 底层通信
    通过 QIODevice(如 QTcpSocket)与客户端进行数据交互,管理数据的异步写入(onBytesWritten() 处理写入进度)

  • 安全控制
    支持 SSL 证书验证(peerCertificate()),提供自动关闭连接的定时器(autoCloseTimer_

典型使用场景
当服务器接受一个新连接时,会创建一个 Session 对象,该对象解析客户端请求并调用相应的回复方法发送响应数据。


2. AbstractManage 类

作用:服务器管理的抽象基类,提供线程池和会话管理的基础设施

核心功能

  • 线程池管理
    维护两个线程池:

    • handleThreadPool_:处理业务逻辑(如调用用户设置的 httpAcceptedCallback_

    • serverThreadPool_:处理网络监听和连接接受(通过 startServerThread()

  • 会话生命周期管理
    跟踪所有活跃的 Session 对象(availableSessions_),提供统一的初始化/反初始化接口(initialize()/deinitialize()

  • 回调机制
    通过 setHttpAcceptedCallback() 允许用户注册自定义请求处理逻辑,当新会话建立时,触发 handleAccepted() 分发到线程池

  • 抽象接口
    定义纯虚函数 onStart() 和 onFinish(),要求子类实现具体的服务器启动/停止逻辑

设计目的
为不同类型的服务器(如 TCP、SSL、Local Socket)提供统一的管理框架,复用线程管理和会话跟踪逻辑。


3. TcpServerManage 类

作用:基于 TCP 协议的 HTTP 服务器具体实现

核心功能

  • TCP 服务器监听
    通过 listen() 方法在指定地址和端口启动 QTcpServer,等待客户端连接

  • 连接处理
    当新连接到达时,创建 Session 对象并调用 newSession(),将其加入管理队列

  • 继承实现
    实现父类 AbstractManage 的纯虚函数:

    • onStart():启动 TCP 服务器

    • onFinish():关闭服务器并清理资源

关键成员

  • QTcpServer* tcpServer_:底层 TCP 服务器实例

  • listenAddress_ 和 listenPort_:监听的地址和端口

使用场景
需快速搭建一个基于 TCP 的 HTTP 服务器时,直接实例化此类并调用 listen() 方法即可。


协作流程示例

  1. 启动服务器
    TcpServerManage 调用 listen() → 触发 onStart() 启动 QTcpServer

  2. 接受连接
    当客户端连接到达 → TcpServerManage 创建 Session 对象,并调用 AbstractManage::newSession()

  3. 处理请求
    AbstractManage 将新会话通过 httpAcceptedCallback_ 回调传递给用户代码,使用 handleThreadPool_ 异步处理

  4. 发送响应
    用户在回调中通过 Session::replyXXX() 方法生成响应数据 → 数据通过 QIODevice 异步发送给客户端

  5. 资源回收
    会话结束时,Session 的 autoCloseTimer_ 或写入完成信号触发资源释放,AbstractManage 维护的 availableSessions_ 自动清理失效会话。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/37168.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

学习笔记 ASP.NET Core Web API 8.0部署到iis

一.修改配置文件 修改Program.cs配置文件将 if (app.Environment.IsDevelopment()) {app.UseSwagger();app.UseSwaggerUI(); }修改为 app.UseSwagger(); app.UseSwaggerUI(); 二.安装ASP.NET Core Runtime 8.0.14 文件位置https://dotnet.microsoft.com/en-us/download/do…

一、小雅自带tutorial文件教程

下载压缩包 这是elegantrl的开源地址: ElegantRL 我使用的是云服务器平台&#xff0c;上传压缩包之后&#xff0c;使用Linux解压缩命令&#xff0c;将压缩包解压。 使用conda新建一个虚拟环境 conda create -n ElegantRL conda activate ElegantRL安装elegantrl包 pip ins…

海康ISAPI协议在智联视频超融合平台中的接入方法

一. 海康ISAPI协议详解 海康ISAPI协议原理 海康ISAPI&#xff08;Internet Server Application Programming Interface&#xff09;协议是海康威视设备提供的一种基于HTTP/HTTPS的高级通信协议&#xff0c;用于实现客户端与设备之间的数据交互。其核心原理包括&#xff1a; 基…

【Azure 架构师学习笔记】- Azure Databricks (22) --Autoloader

本文属于【Azure 架构师学习笔记】系列。 本文属于【Azure Databricks】系列。 接上文 【Azure 架构师学习笔记】- Azure Databricks (21) --费用相关 前言 Databricks家里在Apache Spark之上&#xff0c;是企业级的应对大规模数据处理的通用平台&#xff0c; 可以运行在AWS&a…

论文略读(2025.3.18-更新中)

关于可控视频生成 I2V3D: Controllable image-to-video generation with 3D guidance Image to Video工作&#xff0c;能够实现给一张图&#xff0c;输出一个视频&#xff0c;且可以控制相机。动态信息来自于用户手工设计&#xff08;相机移动&#xff0c;人体骨骼驱动&#x…

Excel导出工具类--复杂的excel功能导出(使用自定义注解导出)

Excel导出工具类 前言: 简单的excel导出,可以用easy-excel, fast-excel, auto-poi,在导出实体类上加上对应的注解,用封装好的工具类直接导出,但对于复杂的场景, 封装的工具类解决不了,要用原生的excel导出(easy-excel, fast-excel, auto-poi都支持原生的) 业务场景: 根据…

神策数据接入 DeepSeek,AI 赋能数据分析与智能运营

在 AI 技术迅猛发展的浪潮下&#xff0c;神策数据正在加速推进人工智能在数据分析和智能运营领域的深度应用。近日&#xff0c;神策数据宣布全面接入 DeepSeek&#xff0c;为企业客户带来更加智能化、高效的数据分析与智能运营服务。这一举措展现了神策数据在人工智能方向的探索…

头歌 JAVA 桥接模式实验

目录 任务描述 实现方式 编程要求 测试说明 代码实现 总结 1 任务描述 某软件公司欲开发一个数据转换工具&#xff0c;可以将数据库中的数据转换成多种文件格式&#xff0c;例如 TXT、XML、PDF 等格式&#xff0c;同时该工具需要支持多种不同的数据库。 本关任务&#…

安全无事故连续天数计算,python 时间工具的高效利用

安全天数计算&#xff0c;数据系统时间直取&#xff0c;安全标准高效便捷好用。 笔记模板由python脚本于2025-03-17 23:50:52创建&#xff0c;本篇笔记适合对python时间工具有研究欲的coder翻阅。 【学习的细节是欢悦的历程】 博客的核心价值&#xff1a;在于输出思考与经验&am…

Docker Swarm集群搭建

Docker Swarm集群搭建 1.准备环境 搭建Docker Swarm集群最低需要准备三台设备&#xff0c;且均需要提前安装好Docker。我这里准备了四台机器用于搭建集群&#xff0c;分别是&#xff1a; DockerSwarm-Node1 lemonDockerSwarm-Node1:~$ docker --version Docker version 28.…

Unity教程(二十二)技能系统 分身技能

Unity开发2D类银河恶魔城游戏学习笔记 Unity教程&#xff08;零&#xff09;Unity和VS的使用相关内容 Unity教程&#xff08;一&#xff09;开始学习状态机 Unity教程&#xff08;二&#xff09;角色移动的实现 Unity教程&#xff08;三&#xff09;角色跳跃的实现 Unity教程&…

麒麟银河V10服务器RabbitMQ安装

安装步骤 rabbitMQ依赖于erlang的环境&#xff0c;所以需要先安装erlang&#xff0c;erlang跟rabbitMQ是有版本之间的关联关系的&#xff0c;根据对应的版本去安装下载&#xff0c;保证少出问题。 可以通过官网来查看RabbitMQ和erlang之间的版本对应关系 rabbitMQ和erlang之间…

让“树和二叉树”埋在记忆土壤中--性质和概念

Nice to meet your! 目录 树的介绍&#xff1a; 树的创建&#xff1a; 二叉树的概念和结构&#xff1a; 二叉树的存储结构&#xff1a; 树的介绍&#xff1a; 概念和结构&#xff1a; 不知你们是否在现实中看见过分为两个叉的枯树&#xff0c;大概长这样&#xff1a; 那…

UDP协议原理

UDP协议原理 本篇介绍 在前面使用UDP编程时已经基本了解了UDP的工作模式&#xff0c;也知道了UDP有三个特点&#xff1a; 无连接不可靠面向数据报 但是当时并没有具体谈论为什么UDP有以上三个特点&#xff0c;基于这个原因&#xff0c;本篇就会针对这三个原因进行介绍 UDP…

关于金融开发领域的一些专业知识总结

目录 1. 交易生命周期 1.1 证券交易所 1.1.1 交易前 1) 订单生成&#xff08;Order Generation&#xff09; 2) 订单管理&#xff08;Order Management&#xff09; 1.1.2 交易执行 3) 交易匹配&#xff08;Trade Matching&#xff09; 1.1.3 交易后 4) 交易确认&…

Flutter运行错误:UG! exception in phase ‘semantic analysis‘

最近在Mac Mini M4上通过Android Studio导入Flutter项目并运行&#xff0c;结果一直跑不起来&#xff0c;错误日志如下&#xff1a; 执行命令查看版本信息&#xff1a; flutter doctor --verbose通过输出信息Java version OpenJDK Runtime Environment (build 21.0.41242208…

DeepSeek + Kimi 自动生成 PPT

可以先用deepseek生成ppt大纲&#xff0c;再把这个大纲复制到Kimi的ppt助手里&#xff1a; https://kimi.moonshot.cn/kimiplus/conpg18t7lagbbsfqksg 选择ppt模板&#xff1a; 点击生成ppt就制作好了。

【C#语言】C#中的同步与异步编程:原理、示例与最佳实践

文章目录 ⭐前言⭐一、同步编程&#xff1a;简单但低效的线性执行&#x1f31f;代码示例&#x1f31f;执行流程示意图&#x1f31f;同步编程特点 ⭐二、异步编程&#xff1a;非阻塞的高效执行&#x1f31f;代码示例&#x1f31f;执行流程示意图&#x1f31f;异步编程核心机制&a…

【MySQL数据库】存储过程与自定义函数(含: SQL变量、分支语句、循环语句 和 游标、异常处理 等内容)

存储过程&#xff1a;一组预编译的SQL语句和流程控制语句&#xff0c;被命名并存储在数据库中。存储过程可以用来封装复杂的数据库操作逻辑&#xff0c;并在需要时进行调用。 类似的操作还有&#xff1a;自定义函数、.sql文件导入。 我们先从熟悉的函数开始说起&#xff1a; …

【sgFloatDialog】自定义组件:浮动弹窗,支持修改尺寸、拖拽位置、最大化、还原、最小化、复位

sgFloatDialog <template><div :class"$options.name" v-if"visible" :theme"theme" :size"size" :style"style"><!-- 托盘头部 --><div class"header" ref"header" dblclick.s…