Qt+QtWebApp开发笔记(一):QtWebApp介绍、下载和搭建基础封装http轻量级服务器Demo

news2024/12/23 19:55:38

若该文为原创文章,转载请注明原文出处
本文章博客地址:https://hpzwl.blog.csdn.net/article/details/130631547

红胖子网络科技博文大全:开发技术集合(包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬结合等等)持续更新中…

Qt开发专栏:三方库开发技术

上一篇:没有了
下一篇:敬请期待…


前言

  在arm上做了Qt的应用程序,为了在局域网实现web页的访问方式来配置arm上Qt的程序,局域网轻量级http服务器是很好的实现方式之一,有机会做国产麒麟上Qt的http服务器,正好接触到了QtWebApp可以实现。
  本篇实战解说QtWebApp的轻量级Demo。
  本篇篇幅较长,为了保持基础的完整性将必要的东西都放在本篇。


Demo

  在这里插入图片描述

下载地址

  链接:https://pan.baidu.com/s/1tSFWCTsbPY5c1rWo2Mxz_Q?pwd=1234


QtWebApp(HTTP Server in C++)

概述

  QtWepApp是一个C++中的HTTP服务器库,其灵感来自Java Servlet。适用于Linux、Windows、Mac OS和Qt Framework支持的许多其他操作系统。
  QtWebApp包含以下组件:

  • HTTP(S)1.0和1.1服务器
  • 模板引擎
  • 缓冲记录器
      这些组件可以相互独立地使用。一个非常小的用法示例:
// The main program starts the HTTP server
int main(int argc, char *argv[])
{
    QCoreApplication app(argc,argv);
        
    new HttpListener(
        new QSettings("configfile.ini", QSettings::IniFormat, &app),
        new MyRequestHandler(&app),
        &app);

    return app.exec();
}


// The request handler receives and responds HTTP requests
void MyRequestHandler::service(HttpRequest& request, HttpResponse& response)
{
    // Get a request parameters
    QByteArray username=request.getParameter("username");

    // Set a response header
    response.setHeader("Content-Type", "text/html; charset=UTF-8");

    // Generate the HTML document
    response.write("<html><body>");
    response.write("Hello ");
    response.write(username);
    response.write("</body></html>");
}

  大约2MB的小内存需求使web服务器有资格用于嵌入式系统(PS:非常符合后续arm产品定位)。对于更大的网络服务来说,它也足够强大。
  记录器通过将调试消息保留在内存中直到出现错误来提高磁盘空间和性能。只要一切正常,就不会编写调试消息。
  对记录器配置的更改将自动变为活动状态,而无需重新启动程序。

  该库使用Qt 4.7至6.x版本运行。如果是Qt 6,则需要安装Qt5Compat库。它包含对许多8位字符编码的支持,Qt6默认情况下不再支持这些编码。可以在LGPL许可证的条件下使用该软件。
作者项目的起源
  多年前,一位经验丰富的Java开发人员坚持认为Java是互联网语言,因为在其他编程语言中进行互联网通信要复杂得多。这不正确,但拒绝相信。所以开始挑战。
  任务:与Qt4相比,仅使用Java 6运行时库对具有一些基本功能的HTTP服务器进行编程。
两个项目都很相似,实现了任务。同时,Qt/C++程序比Java版本小得多,也快得多。
  几年后,用这个原型制作了一个库,并将其用于一些私人项目。大学鼓励发布代码。从那以后,再也不用这个项目了,但还是进行了一些改进,让人们感到高兴。
  有趣的是,Qt制造商多年来一直在开发标准HTTP服务器,但到2022年,它仍然不包括在Qt库中。这也许可以解释为什么很多人使用的库。

QtWebApp下载地址

  官方:http://www.stefanfrings.de/qtwebapp/QtWebApp.zip
  链接:https://pan.baidu.com/s/1v9DTrajX8Mv-xnhScDhN8g?pwd=1234

编写Web服务器应用程序环境

  使用Qt和QtWebApp在C++中开发HTTP Web服务器应用程序。必须已经了解C++和HTML的基本知识。

Windows

  安装好Qt,下载QtWebApp源码;

Linux

  安装好Qt,下载QtWebApp源码,然后对应不同linux安装一些软件如下:

  • Debian, Ubuntu
sudo apt install build-essential gdb libgl1-mesa-dev
  • Fedora, RedHat, CentOS sudo
yum groupDebian, Ubuntunstall "C Development Tools and Libraries"
sudo yum install mesa-libGL-devel
  • openSUSE
sudo zypper install -t pattern devel_basis

运行下载的Demo(这里是ubuntu环境)

  为的编程项目创建一个目录,然后在那里下载并提取QtWebApp ZIP文件。启动QT Creator IDE并打开项目文件Demo1/Demo1.pro。这将打开“配置项目”对话框:
  在这里插入图片描述

  只需点击突出显示的“配置项目”按钮即可。然后点击左边框中的绿色“Run”按钮,构建并运行演示程序。当的计算机正忙时,可以通过单击底部边框中的相关按钮来观看“编译输出”窗格。如果一切正常,将打开一个黑色控制台窗口,告诉演示应用程序正在使用哪个配置文件:
  在这里插入图片描述

  打开URL http://localhost:8080在web浏览器中检查演示web服务器是否正常工作:
  在这里插入图片描述
  如果在屏幕上看到那个网站,所有需要的软件都能正常工作。现在可以关闭演示应用程序。

如何使用QtWebApp

  如果曾经使用Java Servlet API开发过web服务器应用程序,会感觉像在家一样。的库提供了几乎相同的功能。将向展示如何使用QtWebApp编写一个最小的web服务器应用程序。

在自己的程序中构建

  提取编程文件夹中的QtWebApp.zip文件,并创建一个名为“MyFirstWebApp”的新Qt控制台项目(如果尚未完成)。然后,应该拥有与相同的文件夹结构:
  在这里插入图片描述

  将以下行添加到MyFirstWebApp项目的项目文件中:

QT += network
include(../QtWebApp/QtWebApp/httpserver/httpserver.pri)

  第一行激活Qt的网络模块,第二行包括QtWebApp的HTTP服务器模块的源代码。因此,当编译程序时,HTTP服务器将成为可执行文件的一部分。
  在这里插入图片描述
  作为替代方案,可以使用共享库。要生成它,请打开项目QtWebApp/QtWebApp-QtWebApp.pro并构建它。然后查看QtWebApp/Demo2/Demo2.pro,了解如何链接到共享库。然而,建议包含如上所示的源代码,因为这样不太容易出错。

配置参数

  下一步是创建配置文件MyFirstWebApp/etc/webapp1.ini。需要使用操作系统的文件管理器来执行此操作,因为Qt Creator无法创建新文件夹。文件内容为:

[listener]
;host=192.168.0.100
port=8080
minThreads=4
maxThreads=100
cleanupInterval=60000
readTimeout=60000
maxRequestSize=16000
maxMultiPartSize=10000000

  主机和端口参数指定web服务器侦听的IP地址和端口。如果注释掉主机(如上所述),则服务器将侦听所有网络接口。公共web服务器使用端口80,而内部web服务器通常在端口8080上侦听。可以使用任何喜欢的自由端口。
  Unix用户应该记住,1024以下的端口号是为“root”用户保留的。Windows用户可能需要配置Windows防火墙以允许从其他计算机进行访问。
  QtWebApp可以同时处理多个HTTP请求,因此它是多线程的。由于启动一个新线程需要花费大量时间,QtWebApp会将线程重新用于后续的HTTP请求。
  maxThreads值指定并发工作线程的最大数量。在进入生产环境之前,应该使用负载生成器工具来了解服务器在不耗尽内存或变得迟缓的情况下可以处理多少负载。
  minThreads空闲时并发工作线程的最小数量。web服务器总是以一个空线程池开始。线程是在HTTP请求传入时按需创建的。空闲线程由计时器缓慢关闭。每个
cleanupInterval
(以毫秒为单位),服务器都会关闭一个空闲线程,但是minThreads的数量总是保持运行。使用给定的值,的服务器最多可以处理100个并发HTTP连接。它保持4个空闲的工作线程运行,以确保良好的响应时间。
  readTimeout设置通过打开大量连接而不使用这些连接来保护服务器免受简单的拒绝服务攻击的超时时间。空闲连接在该毫秒数之后关闭。在正常情况下,网络浏览器负责关闭连接。
  maxRequestSize保护服务器不受非常大的HTTP请求造成的内存过载的影响。此值适用于常规请求。
  maxMultiPartSize值适用于web浏览器将文件上载到服务器时发生的多部件请求。如果想接收10兆字节的文件,由于HTTP协议开销,必须将此值设置得稍大一些。
  上传的文件存储在临时文件中。临时文件夹的位置由操作系统定义。
  继续创建的第一个web应用程序。要使此配置文件在Qt Creator中可见,请在项目文件中添加一行:

OTHER_FILES += etc/webapp1.ini

  现在添加一些代码来加载该文件:

#include <QCoreApplication>
#include <QSettings>

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);

    QSettings* listenerSettings=
         new QSettings("/home/sfrings/programming/MyFirstWebApp/etc/webapp1.ini",QSettings::IniFormat,&app);
    qDebug("config file loaded");

    return app.exec();
}

  但更喜欢在几个文件夹中自动搜索配置文件,这样就可以在IDE内外运行应用程序,而无需更改路径:

#include <QCoreApplication>
#include <QSettings>
#include <QFile>
#include <QDir>
#include <QString>

/**
 * Search the configuration file.
 * Aborts the application if not found.
 * @return The valid filename
 */
QString searchConfigFile() {
    QString binDir=QCoreApplication::applicationDirPath();
    QString appName=QCoreApplication::applicationName();
    QString fileName("Demo1.ini");

    QStringList searchList;
    searchList.append(binDir);
    searchList.append(binDir+"/etc");
    searchList.append(binDir+"/../etc");
    searchList.append(binDir+"/../"+appName+"/etc");     // for development with shadow build (Linux)
    searchList.append(binDir+"/../../"+appName+"/etc");  // for development with shadow build (Windows)
    searchList.append(QDir::rootPath()+"etc/opt");
    searchList.append(QDir::rootPath()+"etc");

    foreach (QString dir, searchList)
    {
        QFile file(dir+"/"+fileName);
        if (file.exists())
        {
            fileName=QDir(file.fileName()).canonicalPath();
            qDebug("Using config file %s",qPrintable(fileName));
            return fileName;
        }
    }

    // not found
    foreach (QString dir, searchList)
    {
        qWarning("%s/%s not found",qPrintable(dir),qPrintable(fileName));
    }
    qFatal("Cannot find config file %s",qPrintable(fileName));
    return nullptr;
}


int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);

    // Load the configuration file
    QString configFileName=searchConfigFile();
    QSettings* listenerSettings=new QSettings(configFileName, QSettings::IniFormat, &app);
    qDebug("config file loaded");

    return app.exec();
}

  过程searchConfigFile()在多个文件夹中搜索文件。
  方法**QDir::canonicalPath()将相对路径名转换为绝对形式,这在下面的调试消息中看起来更好。
  如果找不到该文件,则应用程序会输出一条带有
qFatal()**的错误消息,这也会中止程序。
一旦加载了配置文件,就可以创建一个HTTP侦听器对象,它是web服务器的核心:

#include <QCoreApplication>
#include <QSettings>
#include <QFile>
#include <QDir>
#include <QString>
#include "httplistener.h"
#include "httprequesthandler.h"

using namespace stefanfrings;

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);
    
    // Load the configuration file
    QString configFileName=searchConfigFile();    
    QSettings* listenerSettings=new QSettings(configFileName, QSettings::IniFormat, &app);
    listenerSettings->beginGroup("listener");
    
    // Start the HTTP server
    new HttpListener(listenerSettings, new HttpRequestHandler(&app), &app);

    return app.exec();
}

  方法**QSettings::beginGroup()**从配置文件中选择组“[listener]”。稍后将添加更多组。
  HttpRequestHandler接收所有传入的HTTP请求,并生成响应。默认情况下,请求处理程序只返回一个错误页面。
  在堆上用“new”创建HttpListener是很重要的,否则它将在程序启动后立即终止。
运行程序并打开URLhttp://localhost:8080在web浏览器中。将在控制台窗口中收到错误页面“501未实现”和调试消息。
  在这里插入图片描述
  这是很多会减慢程序速度的消息,但它们对调试很有帮助。在Qt Creator的左边框中,可以通过单击紫色按钮将构建模式从“调试”更改为“发布”。发布版本不那么冗长:
  在这里插入图片描述

  因此,对于生产,应该更喜欢发布版本。

编写自己的请求处理程序

  为了输出“Hello World”消息,必须编写自己的请求处理程序。用鼠标右键单击src文件夹,选择“添加新…”,然后选择“C++类”。
  在这里插入图片描述

helloworldcontroller.h:

#ifndef HELLOWORLDCONTROLLER_H
#define HELLOWORLDCONTROLLER_H

#include "httprequesthandler.h"

using namespace stefanfrings;

class HelloWorldController : public HttpRequestHandler {
    Q_OBJECT
public:
    HelloWorldController(QObject* parent=0);
    void service(HttpRequest& request, HttpResponse& response);
};

#endif // HELLOWORLDCONTROLLER_H

helloworldcontroller.cpp:

#include "helloworldcontroller.h"

HelloWorldController::HelloWorldController(QObject* parent)
    : HttpRequestHandler(parent) {
    // empty
}

void HelloWorldController::service(HttpRequest &request, HttpResponse &response) {
    response.write("Hello World",true);
}

  可选参数“true”表示这是当前HTTP请求的最后一次write()调用。
main.cpp中的两个更改:

#include "helloworldcontroller.h"

    new HttpListener(listenerSettings,new HelloWorldController(&app),&app);

  运行程序并打开URLhttp://localhost:8080在网络浏览器中。
  在这里插入图片描述


Qt的http服务Demo搭建流程(windows)

  因为http很多时候是放在一个Qt界面里面,所以搭建的是QWidget工程模板,非控制台,有需要自行切换下。

步骤一:下载QtWebApp

略;

步骤二:新建工程testHttpDemo

  在这里插入图片描述

步骤三:拷贝http

  将QtWebApp中的httpserver,符合模块化设计准则,如下图:
  在这里插入图片描述

  添加模块进入工程:
  httpserver模块,QtWebApp自带的三方模块

# httpserver模块,QtWebApp自带的三方模块
include ($$PWD/modules/httpserver/httpserver.pri)

  在这里插入图片描述

  第三方的模块。

步骤四:自建http管理类用模块化

  再建立一个http管理类来处理,如下:
  在这里插入图片描述
  在这里插入图片描述

  再建立基本配置:
  在这里插入图片描述

  至此,基础模块搭建好,下面需要开始写http的消息处理过程。

步骤五:写一个Hello world的展示消息处理

  继承HttpRequestHandler消息处理类,开始新建一个类:
  在这里插入图片描述

  引入头文件,命名空间,做一些基础处理:
  在这里插入图片描述

  在这里插入图片描述

  然后要实现service服务接口:
  在这里插入图片描述

  如下图:
  在这里插入图片描述
  在这里插入图片描述

步骤六:在http运行管理类中启用这个监听

  在这里插入图片描述
  在这里插入图片描述

  在这里插入图片描述
  在这里插入图片描述
  这里已经将http的轻量级服务器已经子线程模块化融入带界面的qt应用中(带不带界面融入过程都一样,只是QApplication和QCoreApplication以及在哪初始化的问题了)

步骤七:测试

  测试127.0.0.1移植连接补上,查看 “入坑二”。
  然后测试打开成功:
  在这里插入图片描述

  这里有个字符编码的问题也要同时解决一下,一般来说都是utf-8,所以要字符编码修改一下。

步骤八:编码一刀切处理

  我们忽略系统编码,统一进行utf-8进行转换,避免因为系统问题而去单独处理这个问题:
  在这里插入图片描述

  然后测试网页:
  在这里插入图片描述

步骤九:打成运行包单独运行再测试服务器

  除了日志,没发现三方模块中有是否监听成功的反馈,所以日志就显得很重要,日志在下一篇再融于进来
  在这里插入图片描述

  至此,一个基础子线程模块化的http服务的qt界面应用Demo就完成了


模块化

  在这里插入图片描述


Demo源码

HttpServerManager.h

#ifndef HTTPSERVERMANAGER_H
#define HTTPSERVERMANAGER_H

#include <QObject>
#include <QMutex>

#include "httplistener.h"
#include "HelloWorldRequestHandler.h"

class HttpServerManager : public QObject
{
    Q_OBJECT
private:
    explicit HttpServerManager(QObject *parent = 0);

public:
    static HttpServerManager *getInstance();

public:
    QString getIp()               const;            // 服务器监听ip(若为空,则表示监听所有ip
    quint16 getPort()             const;            // 服务器监听端口
    int     getMinThreads()       const;            // 空闲最小线程数
    int     getMaxThreads()       const;            // 负载最大线程数
    int     getCleanupInterval()  const;            // 空线程清空间隔(单位:毫秒)
    int     getReadTimeout()      const;            // 保持连接空载超时时间(单位:毫秒)
    int     getMaxRequestSize()   const;            // 最大请求数
    int     getMaxMultiPartSize() const;            // 上载文件最大数(单位:字节)

public:
    void setIp(const QString &ip);                  // 服务器监听ip(若为空,则表示监听所有ip
    void setPort(const quint16 &port);              // 服务器监听端口
    void setMinThreads(int minThreads);             // 空闲最小线程数
    void setMaxThreads(int maxThreads);             // 负载最大线程数
    void setCleanupInterval(int cleanupInterval);   // 空线程清空间隔(单位:毫秒)
    void setReadTimeout(int readTimeout);           // 保持连接空载超时时间(单位:毫秒)
    void setMaxRequestSize(int value);              // 最大请求数
    void setMaxMultiPartSize(int value);            // 上载文件最大数(单位:字节)

public slots:
    void slot_start();
    void slot_stop();

private:
    static HttpServerManager *_pInstance;
    static QMutex _mutex;

private:
    bool _running;

private:
    HttpListener *_pHttpListener;                   // http服务监听器
    QSettings *_pSettings;                          // 配置文件

private:
    QString _ip;                // 服务器监听ip(若为空,则表示监听所有ip)
    quint16 _port;              // 服务器监听端口
    int _minThreads;            // 空闲最小线程数
    int _maxThreads;            // 负载最大线程数
    int _cleanupInterval;       // 空线程清空间隔(单位:毫秒)
    int _readTimeout;           // 保持连接空载超时时间(单位:毫秒)
    int _maxRequestSize;        // 最大请求数
    int _maxMultiPartSize;      // 上载文件最大数(单位:字节)
};
#endif // HTTPSERVERMANAGER_H

HttpServerManager.cpp

#include "HttpServerManager.h"
#include <QApplication>

#include <QDebug>
#include <QDateTime>
//#define LOG qDebug()<<__FILE__<<__LINE__
//#define LOG qDebug()<<__FILE__<<__LINE__<<__FUNCTION__
//#define LOG qDebug()<<__FILE__<<__LINE__<<QThread()::currentThread()
//#define LOG qDebug()<<__FILE__<<__LINE__<<QDateTime::currentDateTime().toString("yyyy-MM-dd")
#define LOG qDebug()<<__FILE__<<__LINE__<<QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss:zzz")

HttpServerManager *HttpServerManager::_pInstance = 0;
QMutex HttpServerManager::_mutex;

HttpServerManager::HttpServerManager(QObject *parent)
    : QObject(parent),
      _pHttpListener(0),
      _pSettings(0),
      _running(false),
      _port(8088),
      _minThreads(2),
      _maxThreads(10),
      _cleanupInterval(60000),
      _readTimeout(60000),
      _maxRequestSize(100),
      _maxMultiPartSize(1024*1024*1024)
{

}

HttpServerManager *HttpServerManager::getInstance()
{
    if(!_pInstance)
    {
        QMutexLocker lock(&_mutex);
        if(!_pInstance)
        {
            _pInstance = new HttpServerManager();
        }
    }
    return _pInstance;
}

void HttpServerManager::slot_start()
{
    if(_running)
    {
        LOG << "It's running!!!";
        return;
    }
    _running = true;
    LOG << "Succeed to run";

    // 启动http的监听
    {
        QString httpServerPath = QString("%1/etc/httpServer.ini").arg(qApp->applicationDirPath());
        if(!_pSettings)
        {
            LOG << httpServerPath << "exit:" << QFile::exists(httpServerPath);
            _pSettings = new QSettings(httpServerPath, QSettings::IniFormat);
        }
#if 0
        if(!_ip.isEmpty())
        {
            _pSettings->setValue("host"           , _ip);  // ;在ini里面是注释了
        }
        _pSettings->setValue("port"            , _port);
        _pSettings->setValue("minThreads"      , _minThreads);
        _pSettings->setValue("maxThreads"      , _maxThreads);
        _pSettings->setValue("cleanupInterval" , _cleanupInterval);
        _pSettings->setValue("readTimeout"     , _readTimeout);
        _pSettings->setValue("maxRequestSize"  , _maxRequestSize);
        _pSettings->setValue("maxMultiPartSize", _maxMultiPartSize);
#endif
        _pHttpListener = new HttpListener(_pSettings, new HelloWorldRequestHandler);
    }
}

void HttpServerManager::slot_stop()
{
    if(!_running)
    {
        LOG <<"It's not running!!!";
        return;
    }
    _running = false;
    LOG << "Succeed to stop";
}

int HttpServerManager::getMaxMultiPartSize() const
{
    return _maxMultiPartSize;
}

void HttpServerManager::setMaxMultiPartSize(int value)
{
    _maxMultiPartSize = value;
}

int HttpServerManager::getMaxRequestSize() const
{
    return _maxRequestSize;
}

void HttpServerManager::setMaxRequestSize(int value)
{
    _maxRequestSize = value;
}

int HttpServerManager::getReadTimeout() const
{
    return _readTimeout;
}

void HttpServerManager::setReadTimeout(int readTimeout)
{
    _readTimeout = readTimeout;
}

int HttpServerManager::getCleanupInterval() const
{
    return _cleanupInterval;
}

void HttpServerManager::setCleanupInterval(int cleanupInterval)
{
    _cleanupInterval = cleanupInterval;
}

int HttpServerManager::getMaxThreads() const
{
    return _maxThreads;
}

void HttpServerManager::setMaxThreads(int maxThreads)
{
    _maxThreads = maxThreads;
}

int HttpServerManager::getMinThreads() const
{
    return _minThreads;
}

void HttpServerManager::setMinThreads(int minThreads)
{
    _minThreads = minThreads;
}

quint16 HttpServerManager::getPort() const
{
    return _port;
}

void HttpServerManager::setPort(const quint16 &port)
{
    _port = port;
}

QString HttpServerManager::getIp() const
{
    return _ip;
}

void HttpServerManager::setIp(const QString &ip)
{
    _ip = ip;
}

HelloWorldRequestHandler.h

#ifndef HELLOWORLDREQUESTHANDLER_H
#define HELLOWORLDREQUESTHANDLER_H

#include "httprequesthandler.h"

using namespace stefanfrings;

class HelloWorldRequestHandler : public HttpRequestHandler
{
public:
    HelloWorldRequestHandler(QObject *parent = 0);

public:
    void service(HttpRequest& request, HttpResponse& response);

private:
    QTextCodec *_pTextCodec;
};

#endif // HELLOWORLDREQUESTHANDLER_H

HelloWorldRequestHandler.cpp

#include "HelloWorldRequestHandler.h"

#include <QTextCodec>

#include <QDebug>
#include <QDateTime>
//#define LOG qDebug()<<__FILE__<<__LINE__
//#define LOG qDebug()<<__FILE__<<__LINE__<<__FUNCTION__
//#define LOG qDebug()<<__FILE__<<__LINE__<<QThread()::currentThread()
//#define LOG qDebug()<<__FILE__<<__LINE__<<QDateTime::currentDateTime().toString("yyyy-MM-dd")
#define LOG qDebug()<<__FILE__<<__LINE__<<QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss:zzz")

using namespace stefanfrings;

HelloWorldRequestHandler::HelloWorldRequestHandler(QObject *parent)
    : HttpRequestHandler(parent)
{
    // 返回文本(我们需要在浏览器上看,所以将Qt内部编码都转成GBK输出即可,不管他本身是哪个编码)
    // WINDOWS: GBK  GB2312
    // LINUX  : urf-8
//    _pTextCodec = QTextCodec::codecForName("utf-8");
    _pTextCodec = QTextCodec::codecForName("GBK");
}

void HelloWorldRequestHandler::service(HttpRequest &request, HttpResponse &response)
{
    LOG;

    // 返回hello world
    QString str = "Hello, world!!!";
    str += "你好, 长沙红胖子 QQ:21497936 www.hpzwl.com";



    // 返回文本(我们需要在浏览器上看,所以将Qt内部编码都转成GBK输出即可,不管他本身是哪个编码)
    QByteArray byteArray = _pTextCodec->fromUnicode(str);
    response.write(byteArray);
}

入坑

入坑一:监听配置代码动态写入失败

问题

  在这里插入图片描述

原因

  在这里插入图片描述
  直接从配置文件读取的配置文件有前缀:
  在这里插入图片描述
  但是还是监听的是端口0,直接读取QtWebApp带过来的配置文件,端口也是0,无法理解直接定位源码:
  在这里插入图片描述
  然后打印一下:
  在这里插入图片描述
  所以把这里调整好,后经过摸索发现,QSettings需要一个文件路径载体,空类路径是无法使用。
  在这里插入图片描述

解决

  在这里插入图片描述

入坑二:127.0.0.1无法进入

问题

  在这里插入图片描述

原因

  配置文件绑定了显性ip。

解决

  在这里插入图片描述

  去掉配置文件显性ip地址:
  在这里插入图片描述

  再尝试:
  在这里插入图片描述


上一篇:没有了
下一篇:敬请期待…


若该文为原创文章,转载请注明原文出处
本文章博客地址:https://hpzwl.blog.csdn.net/article/details/130631547

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

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

相关文章

MySQL学习---16、触发器

1、触发器 MySQL从5.0.2版本开始支持触发器。MySQL的触发器和存储过程一样&#xff0c;都是嵌入到MySQL服务器的一段程序。 触发器是由某个事件来触发某个操作&#xff0c;这些事件包括Insert、Update、Delete事件。所谓事件就是指用户的动作或者触发某项行为。如过定义了触发…

杂记——24.HTML中空格的写法

前几天写项目时&#xff0c;突然对HTML中空格的写法感兴趣&#xff0c;于是搜了一下&#xff0c;现在对其进行总结 HTML不是一种编程语言&#xff0c;而是一种超文本标记语言 (markup language)&#xff0c;是网页制作所必备的。超文本”就是指页面内可以包含图片、链接&#…

PDF文件转换工具Solid Converter PDF 10.1版本在Win10系统的下载与安装配置教程

目录 前言一、Solid Converter PDF安装二、使用配置总结 前言 Solid Converter PDF是一种PDF文件转换工具&#xff0c;可以将PDF文件转换为Microsoft Word、Excel、PowerPoint等格式。它还支持批量转换和OCR&#xff08;光学字符识别&#xff09;功能。 Solid Converter PDF的…

NIO基础

NIO 在学习Netty之前&#xff0c;我们需要先了解一下NIO&#xff0c;以便更好的学习Netty NIO是non-blocking io&#xff0c;也就是非阻塞IO 1.三大组件 1.1 channel & Buffer channel 有一点类似于 stream&#xff0c;它就是读写数据的双向通道&#xff0c;可以从 ch…

【YOLO系列】YOLO v3(网络结构图+代码)

文章目录 网络结构YOLO v3YOLOv3-SPP 多尺度预测损失函数参考 最近在研究YOLO系列&#xff0c;打算写一系列的YOLO博文。在YOLO的发展史中&#xff0c;v1到v3算法思想逐渐完备&#xff0c;后续的系列也都以v3为基石&#xff0c;在v3的基础上进行改进&#xff0c;所以很有必要单…

KD600A变频抗干扰精密介质损耗测量仪

一、产品概述 KD600A变压器介质损耗测试仪是发电厂、变电站等现场自动测量各种高压电力设备介损正切值及电容量的高精度仪器。由于采用了变频技术能保证在强电场干扰下准确测量。仪器采用中文菜单操作&#xff0c;微机自动完成测量。 该仪器同样适用于车间、试验室、科研单位测…

映射及有关概念

映射的概念:有两个集合A,B&#xff0c;若A的任何元素都有唯一的B中元素与之对应&#xff0c;B中元素与之对应的称为像&#xff0c;A中对应的元素称为原像 一个集合也有像&#xff0c;定义为各自像的集合 B中集合也有原像&#xff0c;定义为各自原像的集合 虽然采用了f-1的符号&…

端口隔离、MAC地址表项、MAC地址漂移防止与检测

目录 前言 端口隔离 MAC地址表项 端口安全 MAC地址漂移检测 前言 目前网络中以太网技术的应用非常广泛。然而&#xff0c;各种网络攻击的存在&#xff08;例如针对ARP、DHCP等协议的攻击&#xff09;&#xff0c;不仅造成了网络合法用户无法正常访问网络资源&#xff0c;…

【案例教程】山洪径流过程模拟及洪水危险性评价技术

GIS水文分析&#xff08;ArcHydro、Spatial Anlysist等模块&#xff09;是流域水文模拟建模的重要工具&#xff0c;能够自动提取及计算流域边界、河网水系、流向、汇流时间和其它流域特征参数。美国陆军工程兵团开发的开源、免费Hec-RAS软件具有强大的空间数据分析与整合功能、…

每日学术速递5.13

CV - 计算机视觉 | ML - 机器学习 | RL - 强化学习 | NLP 自然语言处理 Subjects: cs.CV 1.VideoChat: Chat-Centric Video Understanding 标题&#xff1a;VideoChat&#xff1a;以聊天为中心的视频理解 作者&#xff1a;KunChang Li, Yinan He, Yi Wang, Yizhuo Li, Wen…

计算机网络基础知识(五)——什么是TCPUDP协议?图文并茂的方式对两大传输层协议进行从头到尾的讲解

文章目录 01 | &#x1f4d5; 什么是 T C P &#xff1f; \color{red}{什么是TCP&#xff1f;} 什么是TCP&#xff1f;&#x1f4d5;特点三次握手 && 四次挥手超时重传滑动窗口 02 | &#x1f4d9; 什么是 U D P &#xff1f; \color{orange}{什么是UDP&#xff1f;} 什…

1. 链表

b站懒猫数据结构课程笔记&#xff1a;https://www.bilibili.com/read/cv8013121?spm_id_from333.999.0.0 一、链表的概念 单链表&#xff1a;线性表的链接存储结构 单链表存储特点&#xff1a; 逻辑次序和物理次序不一定相同 元素之间的逻辑关系用指针表示 举例&#xff1a…

PASCAL VOC数据集

一、前言 之前寒假好像就学了&#xff0c;但是没有记笔记&#xff0c;现在看来还是得记笔记&#xff0c;都忘得差不多了啊。 二、数据集的介绍 2.1数据集背景 分类类别 2.2数据集文件结构&#xff1a; 2.3文件夹 2.3.1Annotations文件夹 对于标注文件Annotations&#xff1a;里…

基于SpringBoot框架的程序开发步骤

SpringBoot简介 1. 入门案例问题导入1.1 入门案例开发步骤1.2 基于SpringBoot官网创建项目1.3 SpringBoot项目快速启动 2. SpringBoot概述问题导入2.1 起步依赖2.2 辅助功能 1. 入门案例 问题导入 SpringMVC的HelloWord程序怎么写&#xff1f; SpringBoot是由Pivotal团队提供…

死锁、生产者和消费者问题

目录 生产者和消费者问题 死锁的概念 内存的基础知识 内存管理的概念 覆盖与交换 介绍一下PCB 连续分配管理方式​编辑 生产者和消费者问题 死锁的概念 什么是死锁 进程死锁、饥饿、死循环的区别 死锁产生的必要条件 什么时候会发生死锁 死锁的处理策略 内存的基础知识 内存…

微三云润秋带你解析商城分销系统

管理大师德鲁克曾说过&#xff1a;当今企业间的竞争&#xff0c;不是产品之间的竞争&#xff0c;而是商业模式之间的竞争。创业不只是项目选择重要&#xff0c;好的商业模式同样重要&#xff0c;如果没有好的商业模式&#xff0c;企业将会被淘汰。 今天我们要聊的这个商城就有点…

怎样设置CRM目标?有什么作用?

实施CRM系统可以帮助企业提高客户保留率&#xff0c;增加收入&#xff0c;并推动业绩增长。然而&#xff0c;在实施CRM系统之前&#xff0c;必须设定明确的目标&#xff0c;与企业的整体战略保持一致。在这篇文章中&#xff0c;我们来讨论实施CRM目标是什么&#xff0c;如何设定…

基于AD9172/AD9176的4 通道12.6GSPS 采样率16 位DA 播放FMC JESD204B 接口子卡模块

板卡概述 FMC_XM131 是一款4 通道12.6GSPS 采样率16 位DA 播放FMC子卡模块&#xff0c;该板卡为FMC标准&#xff0c;符合VITA57.4 规范&#xff0c;可以作为一个理想的IO 模块耦合至FPGA 前端&#xff0c;16 通道的JESD204B 接口通过FMC连接器连接至FPGA 的高速串行端…

【Python TurboGears】零基础也能轻松掌握的学习路线与参考资料

Python TurboGears是一款开源的web框架&#xff0c;它篮了多种Python库和工具&#xff0c;可以更容易地开发和维护web应用程序。TurboGears具有优秀的文档和活跃的社区支持&#xff0c;是学习web开发的理想选择之一。以下是Python TurboGears学习路线&#xff0c;参考资料和优秀…

一句话简短解析 jsjiami.v6

jsjiami.v6 是一种广泛使用的 JavaScript 代码混淆工具&#xff0c;它提供了多种代码混淆技术&#xff0c;包括变量名重命名、函数名重构、字符串替换、代码结构混淆等&#xff0c;可以将代码转换为难以理解和阅读的形式。在本文中&#xff0c;我们将对 jsjiami.v6 进行分析&am…