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

news2024/10/6 5:55:40

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/WebApi1

    HttpRequestHandler *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 store
    QSettings *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 listener
    QSettings *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.coloradmin.cn/o/1632779.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

值得收藏!AMI BIOS蜂鸣声代码一览表,让你在排除故障时有的放矢

序言 AMI BIOS是美国Megatrends公司生产的一种BIOS。许多流行的主板制造商已经将AMI的BIOS集成到他们的系统中。 其他主板制造商已经创建了基于AMI BIOS系统的自定义BIOS软件。基于AMI BIOS的BIOS发出的蜂鸣声代码可能与下面的真实AMI BIOS蜂鸣声代码完全相同,也可能略有不同…

Eclipse内存分析器 Java内存分析工具MAT(Memory Analyzer Tool)的介绍与使用

1.visualvm实时监测 2.Memory Analyzer Tool打开 3.工具的使用可以参考 Java内存分析工具MAT(Memory Analyzer Tool)的介绍与使用 ------------------------ 1.我远程发现是其中一个客户端A请求服务器页面响应&#xff0c;一直得不到响应&#xff0c;然后客户端A一直请求&am…

C语言——字符串和字符串函数

一、字符串 实际上C语言中实际上是没有内置的字符串类型的&#xff0c;大部分字符串都是以字符型数组和常量字符串的形式存在的。 字符串可以通过多种方式在C语言中声明和初始化&#xff1a; 直接初始化&#xff1a; char greeting[] "Hello, world!"; 在这个例…

0417GoodsImgTomCat项目 实现添加储存图片 分页查询图片

0417GoodsImgTomCat项目包-CSDN博客 数据库字段&#xff1a; 界面效果

【Vivado那些事儿】使用 Python 提取 ILA 数据

ILA应该是调试AMD-Xilinx FPGA最常用的IP。 在调试中&#xff0c;我们希望 ILA 中的波形可以提供有关设计问题的所有信息&#xff0c;但情况并非如此。对于复杂的调试&#xff0c;我们还需要将 ILA 捕获的真实数据存储到可以进一步处理的文件中。根据放置 ILA 的位置&#xff0…

笔试刷题-Day10

牛客 一、DP30买卖股票的最好时机&#xff08;一&#xff09; 算法&#xff1a;虽然题目标了DP但是用贪心更快页更容易理解 import java.util.Scanner;// 注意类名必须为 Main, 不要有任何 package xxx 信息 public class Main {public static void main(String[] args) {Sca…

场外个股期权开户新规及操作方法

场外个股期权开户新规 场外个股期权开户新规主要涉及对投资者资产实力、专业知识、风险承受能力和诚信记录的要求。以下是根据最新规定总结的关键要点&#xff1a; 来源/&#xff1a;股指研究院 资产门槛&#xff1a;投资者需具备一定的资产实力&#xff0c;确保在申请开户前…

十五、freeRTOS_移植与内部实现

1.链表操作 1.1普通链表操作 #include "usart.h"#include <stdio.h> #include <string.h> #include <stdlib.h>struct person {char *name;int age;struct person *couple; };struct person w; struct person h;int main(int argc, char **arg) …

【免费Java系列】给大家出一些JavaSE基础第八天的内容案例 , 让大家更好的理解与掌握

String字符串 案例一 求取字符串的长度 public class Main {public static void main(String[] args) {String str "Hello World";String substring str.substring(6);System.out.println("截取后的字符串为&#xff1a;" substring);} }输出结果&…

使用新版ESLint,搭配Prettier使用的配置方式

概述 ESLint重大更新(9.0.0版本)后,将不再支持非扁平化配置文件,并且移除了与Prettier冲突的规则,也就是说与Prettier搭配使用,不再需要使用插件“eslint-config-prettier”来处理冲突问题。 注:使用新版的前提条件是Node.js版本必须是18.18.0、20.9.0,或者是>=21.1…

DiffSeg——基于Stable Diffusion的无监督零样本图像分割

概述 基于计算机视觉的模型的核心挑战之一是生成高质量的分割掩模。大规模监督训练的最新进展已经实现了跨各种图像风格的零样本分割。此外&#xff0c;无监督训练简化了分割&#xff0c;无需大量注释。尽管取得了这些进展&#xff0c;构建一个能够在没有注释的零样本设置中分…

解码Android应用:探索apk.sh的简化反向工程之道

解码Android应用&#xff1a;探索apk.sh的简化反向工程之道 引言 在当今数字化时代&#xff0c;Android应用的反向工程变得越来越重要。无论是应用开发者还是安全研究人员&#xff0c;都需要深入了解应用的内部结构和行为。然而&#xff0c;传统的反向工程过程常常繁琐复杂&a…

WiTUnet:一种集成CNN和Transformer的u型架构,用于改进特征对齐和局部信息融合

WiTUnet:一种集成CNN和Transformer的u型架构&#xff0c;用于改进特征对齐和局部信息融合 摘要IntroductionRelated workMethod WiTUnet: A U-Shaped Architecture Integrating CNN and Transformer for Improved Feature Alignment and Local Information Fusion. 摘要 低剂量…

LT6911UXB HDMI2.0 至四端口 MIPI DSI/CSI,带音频 龙迅方案

1. 描述LT6911UXB 是一款高性能 HDMI2.0 至 MIPI DSI/CSI 转换器&#xff0c;适用于 VR、智能手机和显示应用。HDMI2.0 输入支持高达 6Gbps 的数据速率&#xff0c;可为4k60Hz视频提供足够的带宽。此外&#xff0c;数据解密还支持 HDCP2.2。对于 MIPI DSI / CSI 输出&#xff0…

谁获得了全国交通运输行业最高科技奖项???

近期&#xff0c;2023年度中国交通运输协会科学技术奖表彰大会暨中国交通运输新技术新成果推广大会在株洲举办。会上&#xff0c;由交通运输部管理干部学院牵头&#xff0c;上海梦创双杨数据科技有限公司、深圳开源互联网安全技术有限公司、中国民航管理干部学院、北京信德科技…

SpringCloud Alibaba Nacos简单应用(三)

文章目录 SpringCloud Alibaba Nacos创建Nacos 的服务消费者需求说明/图解创建member-service-nacos-consumer-80 并注册到NacosServer8848创建member-service-nacos-consumer-80修改pom.xml创建application.yml创建主启动类业务类测试 SpringCloud Alibaba Nacos 创建Nacos 的…

爱国者随身wifi VS格行随身wifi对比测评!随身wiif哪个品牌好用?排名第一名随身WiFi格行随身WiFi真的靠谱吗?随身WiFi热销榜第一名!

出门手机信号不好网络卡顿&#xff0c;手机流量不够用&#xff0c;相信这是很多朋友都会遇到的问题。为了解决这个问题更多的会选择随身wifi&#xff0c;但是市面上随身wifi品牌众多&#xff0c;有不知道该选择哪一款。今天就来看看爱国者随身wifi和格行随身wifi哪款更好用&…

给我推荐5个非常好用的AI绘图生成软件

绘画领域随着科技的进步也得以革新&#xff0c;其中AI绘画软件是最为显著的创新之一。本文为大家推荐了5个极具实用价值的AI绘图生成软件&#xff0c;一同来看看吧&#xff01; 爱制作AI 功能介绍&#xff1a; 这款软件可以根据用户提供的图片或描述生成艺术绘画作品。它使用…

Graph Neural Networks(GNN)学习笔记

本学习笔记的组织结构是&#xff0c;先跟李沐老师学一下&#xff0c;再去kaggle上寻摸一下有没有类似的练习&#xff0c;浅做一下&#xff0c;作为一个了解。 ———————————0428更新—————————————— 课程和博客看到后面准备主要看两个&#xff1a;GCN和…

24.4.28(板刷dp,拓扑判环,区间dp+容斥算回文串总数)

星期一&#xff1a; 昨晚cf又掉分&#xff0c;小掉不算掉 补ABC350 D atc传送门 思路&#xff1a;对每个连通块&#xff0c;使其成为一个完全图&#xff0c;完全图的边数为 n*(n-1)/2 , 答案加上每个连通块成为完全图后的…