QT httpServer多线程后台服务器的例子实现

1.需求

1.1 用户需要其他平台(web端)调用Qt平台的接口,获取想要的数据并实时显示在网页里,比如实时的温湿度,用户数据等

1.2 用户需要在其他平台(web端)调用Qt平台的接口,下发数据给本地QT客户端显示,如下发用户数据,下发任务等

2.解决方案

这是就需要一个类似httpServer的服务端了,实时监听端口,随时接收web平台的请求,根据请求内容,接收平台下发的数据并存储到本地客户端显示,或者根据请求,上传需要的信息给web平台

现成的接口是没有的,需要自己写,底层本质都是基于QWebServer加上多线程封装实现的,轮子是已经有的,已经造好了,我们用就行了,想深入了解的,可以看源码的实现

我就挂在下面的链接里了,开源的Qt httpServer代码,里面有很多

链接: https://pan.baidu.com/s/1SHqSCGiGQblur69oCz_LXg?pwd=1234 提取码: 1234 

 3. 实现

建立一个WebServerApi的工程项目,没有界面的,一般后台服务都是没有界面的,更加轻便,反应快,可以建立控制台项目或者动态库/插件库,都可以,我这里用来演示,就用控制台项目演示了

建好工程项目后,在有了已经写好的轮子基础上,就简单了,先把需要的httpServer文件引入程序目录里

然后建一个WebApi1的类,用来表示一个接口类,专门处理Api1接口的内容

#ifndef WEBAPI1_H
#define WEBAPI1_H#include "httprequesthandler.h"
using namespace stefanfrings;class WebApi1: public HttpRequestHandler
{
public:WebApi1(QObject *parent = nullptr);void service(HttpRequest &request, HttpResponse &response) override;QJsonObject changeByteArrayToJsonObject(const QByteArray &ba);
};#endif // WEBAPI1_H
#include "webapi1.h"
#include <QJsonObject>
#include <QJsonDocument>WebApi1::WebApi1(QObject *parent)
{}void WebApi1::service(HttpRequest &request, HttpResponse &response)
{QString path = request.getPath();QStringList pathList = path.split("/");//QString interfaceName = pathList.value(3);if (pathList.size()<3) {this->returnError(response);return;}QString method = pathList.value(3);QByteArray responseMsg;if(method == "getUserInfo") {QJsonObject obj;obj.insert("name", "小明");obj.insert("age", 18);obj.insert("success", true);responseMsg =  QJsonDocument(obj).toJson();}else if(method == "setUserInfo") {auto recvData = request.getBody();QJsonObject data = changeByteArrayToJsonObject(recvData);QString name = data.value("name").toString();int age = data.value("name").toInt();qDebug()<<QString("收到平台下发用户信息,name:%1,age:%2").arg(name).arg(age);QJsonObject obj;obj.insert("success", true);responseMsg =  QJsonDocument(obj).toJson();}else {QJsonObject obj;obj.insert("error", "没有这个方法");obj.insert("success", false);responseMsg =  QJsonDocument(obj).toJson();}response.write(responseMsg);
}QJsonObject WebApi1::changeByteArrayToJsonObject(const QByteArray &ba)
{// 将数据转化成json内容QJsonParseError jsonpe;QJsonDocument json = QJsonDocument::fromJson(ba, &jsonpe);if (jsonpe.error == QJsonParseError::NoError) {if (json.isObject()) {QJsonObject obj = json.object();if (obj.contains("error")) {qDebug() << "error:" << obj["error"];return QJsonObject();} else {return obj;}} else {qDebug() << "error, shoud json object";return QJsonObject();}} else {qDebug() << "error:" << jsonpe.errorString();return QJsonObject();}
}

然后在建一个WebApi2的接口类,同上,名字不一样而已,我用来演示

在建一个RequestMapper类,用来做请求映射的管理,也就是对于每一个不同类型接口,可以根据定义好的类型来做出相应的处理,内容如下:

#ifndef REQUESTMAPPER_H
#define REQUESTMAPPER_H#include "httprequesthandler.h"using namespace stefanfrings;class RequestMapper : public HttpRequestHandler
{
public:RequestMapper(QObject *parent = nullptr);~RequestMapper() override;void service(HttpRequest &request, HttpResponse &response) override;private:QHash<QString, HttpRequestHandler *> m_requestMap;};#endif // REQUESTMAPPER_H
#include "requestmapper.h"
#include <QDateTime>
#include "webapi1.h"
#include "webapi2.h"RequestMapper::RequestMapper(QObject *parent)
{m_requestMap.insert("WebApi1", new WebApi1(this));m_requestMap.insert("WebApi2", new WebApi2(this));
}RequestMapper::~RequestMapper() {qDeleteAll(m_requestMap);m_requestMap.clear();
}void RequestMapper::service(HttpRequest &request, HttpResponse &response) {response.setHeader("Access-Control-Allow-Origin", "*");response.setHeader("Access-Control-Allow-Credentials", "true");response.setHeader("P3P", "CP=CAO PSA OUR");if (!request.getHeader("Access-Control-Request-Method").isNull() && request.getMethod() == "OPTIONS") {response.setHeader("Access-Control-Allow-Methods", "POST,GET,TRACE,OPTIONS");response.setHeader("Access-Control-Allow-Headers", "Content-Type,Origin,Accept");response.setHeader("Access-Control-Max-Age", 86400);}response.setHeader("Content-Type", "application/json;charset=utf-8");response.setHeader("Date", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss").toUtf8());QString path = request.getPath();QStringList pathList = path.split("/");// 因为path以/为开头,使用split,第一个元素为空串if (pathList.size() < 3+1) {this->returnError(response);return;}if (pathList.value(1) != "Stms") {this->returnError(response);return;}// 如请url后缀为 /test/Stms/WebApi1HttpRequestHandler *handler = m_requestMap.value(pathList.value(2));if (handler != nullptr) {handler->service(request, response);} else {this->returnError(response);}
}
在建立一个WebApiManager的管理类,内容如下
#ifndef WEBAPIMANAGER_H
#define WEBAPIMANAGER_H#include <QObject>class WebApiManager: public QObject
{
public:WebApiManager(QObject *parent = nullptr);void init();
};#endif // WEBAPIMANAGER_H
#include "webapimanager.h"
#include "requestmapper.h"
#include "httplistener.h"
#include "httpsessionstore.h"
#include "staticfilecontroller.h"
#include <QCoreApplication>
#include <QSettings>StaticFileController* s_staticFileController = nullptr;using namespace stefanfrings;WebApiManager::WebApiManager(QObject *parent): QObject(parent)
{}void WebApiManager::init()
{QString configFileName = QCoreApplication::applicationDirPath() + "/config/WebConfig.ini";// Configure logging into a file
//    QSettings *logSettings = new QSettings(configFileName, QSettings::IniFormat, this);
//    logSettings->beginGroup("logging");
//    auto logger = new FileLogger(logSettings, 10000, this);
//#ifndef QT_DEBUG
//    logger->installMsgHandler();
//#endif// Configure session storeQSettings *sessionSettings = new QSettings(configFileName, QSettings::IniFormat, this);sessionSettings->beginGroup("sessions");new HttpSessionStore(sessionSettings, this);// Configure static file controller//    QSettings *fileSettings = new QSettings(configFileName, QSettings::IniFormat, this);//    fileSettings->beginGroup("docroot");//    s_staticFileController = new StaticFileController(fileSettings, this);// Configure and start the TCP listenerQSettings *listenerSettings = new QSettings(configFileName, QSettings::IniFormat, this);listenerSettings->beginGroup("listener");new HttpListener(listenerSettings, new RequestMapper(this), this);
}

 在init()的函数中,初始化了webServer的配置信息,这里用的是配置文件(WebConfig.ini)的方式进行配置,如监听的端口,还有一些其他的配置 

配置文件内容如下,可配置监听的端口,线程数等,还有其他的信息不就不解析了,想知道的可以去查

[listener]
host=0.0.0.0
#监听端口
port=8080
#最小线程数量
minThreads=4
#最大线程数量
maxThreads=100
#自动清理延时
cleanupInterval=60000
#读取超时时长
readTimeout=60000
#证书秘钥文件
#sslKeyFile=../../static/certChain/devkey.pem
#证书文件
#sslCertFile=../../static/certChain/devcert.pem
#最大请求长度
maxRequestSize=500000
#最大多包大小
maxMultiPartSize=10000000[templates]
path=templates
suffix=.tpl
encoding=UTF-8
cacheSize=1000000
cacheTime=60000[docroot]
#页面静态内容位置
path=../../static
#编码
encoding=UTF-8
#cookie存活时间
maxAge=60000
#缓存保持时间
cacheTime=60000
#缓存大小
cacheSize=1000000
#最大单个缓存文件大小
maxCachedFileSize=65536[sessions]
#session超时时间
expirationTime=600000
#默认cookie名称
cookieName=sessionid
#默认cookie地址
cookiePath=/
#默认cookie说明
cookieComment=Identifies the user
;cookieDomain=stefanfrings.de[logging]
; The logging settings become effective after you comment in the related lines of code in main.cpp.
#log输出路径
fileName=../../logs/webRuntime.log
#最小输出等级(0=DEBUG, 1=WARNING, 2=CRITICAL, 3=FATAL, 4=INFO)
minLevel=1
#缓冲区大小
bufferSize=100
#日志文件大小
maxSize=1000000
#日志最大备份数量
maxBackups=2
#日志时间格式
timestampFormat=yyyy-MM-dd hh:mm:ss.zzz
;msgFormat={timestamp} {typeNr} {type} {thread} {msg}
#日志内容格式
msgFormat={timestamp} {typeNr} {type} {thread} {msg}\n  in {file} line {line} function {function}
; QT5 supports: msgFormat={timestamp} {typeNr} {type} {thread} {msg}\n  in {file} line {line} function {function}[socketserver]
host=127.0.0.1
port=8160

记得把文件放在程序目录下

编译运行启动程序,监听端口

然后用浏览器请求这个服务器,获取想要的内容

这个多线程好用的httpserver就弄好了,不怎么懂的,可以断点调试,慢慢理解,提升蛮大的

有什么不懂的,可以评论区留言

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

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

相关文章

贝叶斯统计实战:Python引领的现代数据分析之旅

贝叶斯统计这个名字取自长老会牧师兼业余数学家托马斯贝叶斯(Thomas Bayes&#xff0c;1702—1761)&#xff0c;他最先推导出了贝叶斯定理&#xff0c;该定理于其逝世后的1763年发表。但真正开发贝叶斯方法的第一人是Pierre-Simon Laplace(1749—1827)&#xff0c;因此将其称为…

Copilot Venture Studio創始合伙人楊林苑確認出席“邊緣智能2024 - AI開發者峰會”

隨著AI技術的迅猛發展&#xff0c;全球正逐步進入邊緣計算智能化與分布式AI深度融合的新時代&#xff0c;共同書寫著分布式智能創新應用的壯麗篇章。邊緣智能&#xff0c;作為融合邊緣計算和智能技術的新興領域&#xff0c;正逐漸成為推動AI發展的關鍵力量。借助分布式和去中心…

Messari 报告摘要 :Covalent Network(CQT)2024 年第一季度表现

摘要&#xff1a; 尽管 CQT 代币流通供应量增加了 20%&#xff08;新增 1.04 亿枚 CQT&#xff09;&#xff0c;但 CQT 的质押百分比仅从 2023 年第一季度的 22% 增长到了 2024 年第一季度的 29%。 CQT 的市值季度环比增长了 28%&#xff0c;多次达到 2.75 亿美元&#xff0c…

分享三款可以给pdf做批注的软件

PDF文件不像Word一样可以直接编辑更改&#xff0c;想要在PDF文件上进行编辑批注需要用到一些专业的软件&#xff0c;我自己常用的有三款&#xff0c;全都是官方专业正版的软件&#xff0c;功能丰富强大&#xff0c;使用起来非常方便&#xff01; 1.edge浏览器 这个浏览器不仅可…

van-cascader(vant2)异步加载的bug

问题描述&#xff1a;由于一次性返回所有的级联数据的话&#xff0c;数据量太大&#xff0c;接口响应时间太久&#xff0c;因此采用了异步加载的方案&#xff0c;看了vant的官方示例代码&#xff0c;照着改了下&#xff0c;很轻松地实现了功能。正当我感叹世界如此美好的时候&a…

2.2 Java全栈开发前端+后端(全栈工程师进阶之路)-前端框架VUE3-基础-Vue基本语法

文本渲染指令 文本渲染指令-v-html与v-text Vue使用了基于HTML的模板语法&#xff0c;允许开发者声明式地将DOM绑定至底层Vue实例的数据。所有Vue的模板都是 合法的HTML&#xff0c;所以能被遵循规范的浏览器和HTML解析器解析。 在前面&#xff0c;我们一直使用的是字符串插…

Flutter - 折叠面板

demo 地址: https://github.com/iotjin/jh_flutter_demo 代码不定时更新&#xff0c;请前往github查看最新代码 flutter 自定义折叠组件 支持三种类型和两种展示效果可自定义title和被折叠的内容 效果图 示例 import package:flutter/material.dart; import /jh_common/widge…

springboot+websocket开发简单的在线群聊聊天web版本

springbootwebsocket开发简单的在线群聊聊天web版本&#xff01;近期在测试websocket插件的群聊功能。下面是一个简单的demo。分享给大家&#xff0c;亲测可以使用的。 1&#xff1a;首先是一个chat.html页面。代码如下&#xff1a; <!DOCTYPE html> <html lang"…

Linux的Shell脚本详解

本文目录 一、什么是 Shell 脚本文件 &#xff1f;二、编写Shell脚本1. 基本规则2. shell 变量&#xff08;1&#xff09;创建变量&#xff08;2&#xff09;引用变量&#xff08;3&#xff09;删除变量&#xff08;4&#xff09;从键盘读取变量&#xff08;5&#xff09;特殊变…

VMware安装ubuntun虚拟机使用桥接模式无法上网问题解决

问题&#xff1a;最近准备使用VMware虚拟机搭建k8s集群服务&#xff0c;因为需要在同一个网段下&#xff0c;我使用桥接的方式&#xff0c;我发现主机在使用有线连接时虚拟机网络连接正常&#xff0c;但是使用无线网就显示连接不上网络。 解决方法 一、查看网络连接&#xff…

MFC 列表控件删除实例(源码下载)

1、本程序基于前期我的博客文章《MFC下拉菜单打钩图标存取实例&#xff08;源码下载) 》 2、程序功能选中列表控件某一项&#xff0c;删除按钮由禁止变为可用&#xff0c;点击删除按钮&#xff0c;选中的项将删除。 3、首先在主界面添加一个删除参数按钮。 4、在myDlg.cpp 文件…

蓝桥杯练习系统(算法训练)ALGO-951 预备爷的悲剧

资源限制 内存限制&#xff1a;512.0MB C/C时间限制&#xff1a;1.0s Java时间限制&#xff1a;3.0s Python时间限制&#xff1a;5.0s 问题描述 英语预备爷gzp是个逗(tu)比(hao)&#xff0c;为了在即将到来的英语的quiz中不挂科&#xff0c;gzp废寝忘食复习英语附录单词…

基于缓存注解的时间戳令牌防重复提交设计

文章目录 一&#xff0c;概述二&#xff0c;实现过程1、引入pom依赖2、定义缓存管理3、时间戳服务类4、模拟测试接口 三&#xff0c;测试过程1&#xff0c; 模拟批量获取2&#xff0c; 消费令牌 四&#xff0c;源码放送五&#xff0c;优化方向 一&#xff0c;概述 API接口由于…

PHP源码_最新Ai对话系统网站源码 ChatGPT+搭建教程+前后端

基于ChatGPT开发的一个人工智能技术驱动的自然语言处理工具&#xff0c;它能够通过学习和理解人类的语言来进行对话&#xff0c;还能根据聊天的上下文进行互动&#xff0c;真正像人类一样来聊天交流&#xff0c;甚至能完成撰写邮件、视频脚本、文案、翻译、代码&#xff0c;写论…

C++Day6作业

1、模板实现顺序栈 #include <iostream>using namespace std;template <typename T> class Stack {T* S; //数组int size;//栈容量int top; //栈顶元素下标 public://有参构造Stack(int size):S(new T[size]),size(size),top(-1){}//初始化时直接将栈顶元素下标设…

记一次古董级netapp存储更换故障硬盘全过程

1、案例背景 记一次某医院PACS存储NetApp FAS2554更换故障硬盘的过程。 这个netapp设备以前从未调试过&#xff0c;据客户说该设备上线也有快9年了&#xff0c;头一次故障硬盘。因为己经过保了&#xff0c;客户只是采购的硬盘&#xff0c;我这来免费服务了。。。 netapp调试…

LeetCode 110.平衡二叉树(Java/C/Python3/Go实现含注释说明,Easy)

标签 树深度优先搜索递归 题目描述 给定一个二叉树&#xff0c;判断它是否是高度平衡的二叉树。 本题中&#xff0c;一棵高度平衡的二叉树定义为&#xff1a; 一个二叉树每个节点的左右两个子树的高度差的绝对值不超过1。 原题&#xff1a;LeetCode 110.平衡二叉树 思路及…

『跨端框架』Flutter环境搭建

『跨端框架』Flutter环境搭建 资源网站简介跨平台高性能发展历程跨平台框架的比较成功案例 环境搭建&#xff08;windows&#xff09;基础环境搭建Windows下的安卓环境搭建Mac下的安卓环境配置资源镜像JDKAndroid StudioFlutter SDK问题一问题二问题三修改项目中的Flutter版本 …

Android14之解决报错:libncurses.so.5与libtinfo.so.5缺少问题(二百零九)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…

【数据库主从架构】

【数据库主从架构】 1. 什么是数据库的主从架构1.1 主从复制1.1.1 MySQL的主从主从复制技术三级目录 1. 什么是数据库的主从架构 随着公司业务线的增多&#xff0c;各种数据都在迅速增加&#xff0c;并且数据的读取流量也大大增加&#xff0c;就面临着数据安全问题&#xff0c;…