当前位置:首页 » 《休闲阅读》 » 正文

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

4 人参与  2024年09月06日 08:09  分类 : 《休闲阅读》  评论

点击全文阅读


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=templatessuffix=.tplencoding=UTF-8cacheSize=1000000cacheTime=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.1port=8160

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

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

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

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

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


点击全文阅读


本文链接:http://zhangshiyu.com/post/155989.html

<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1