QHttpServer 填坑

本文介绍了从github下载的开源库QHttpServer,照搬其示例代码在客户端多且同时访问服务端时会出现冲突崩溃问题。为避免此情况,需创建专门处理客户端请求的类。同时,为防止网络中断导致对象无法释放,应做请求计数并维护链表,还给出了改进后的代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

QHttpServer 是我从github 下载的一个开源库

下面的代码是我在网上看到用这个库做的一个项目的部分代码,曾因为照搬这个例子,导致应用出现了很大的问题。

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    http = new QHttpServer();
    connect(http, &QHttpServer::newRequest, this, &MainWindow::request);
    http->listen(QHostAddress::Any, 8087);
}

void MainWindow::request(QHttpRequest *req, QHttpResponse *resp)
{
    m_req = req;
    m_resp = resp;
    connect(req, &QHttpRequest::data, this, &MainWindow::appendBody);
    connect(req, &QHttpRequest::end, this, &MainWindow::end);
}

void MainWindow::appendBody(const QByteArray &body)
{
    m_body += body;
}

void MainWindow::end()
{
    qDebug()<< m_body;
    m_resp->setHeader("Content-Length", QString::number(m_body.size()));
    m_resp->writeHead(200);
    m_resp->end(m_body);

    m_req->deleteLater();
    m_resp->deleteLater();
    m_req = nullptr;
    m_resp = nullptr;
}

首先是在构造函数中,创建 http 服务,监听8087 端口。然后在 request 槽函数中,绑定槽函数 appendBody 和 end 。 一切看似正常,对于小程序,并且是服务端与客户端一对一的时候,的确是没啥大问题。但当客户端多,且需要同时访问服务端的时候,会发生什么呢?

在这里插入图片描述
就像上面的图,大家同时访问服务器,但我们保存客户端请求的指针只有一个,这势必会造成冲突,引起混乱,崩溃也是意料之中。
所以为避免这种情况,我们需要一个专门处理客户端请求的类,当接收到客户端请求时,就新建一个这样的对象,去处理请求的数据,处理完成自动释放自己,每一个客户端的请求都有一个专门的对象负责,这样才不会打架嘛。
还有,网络拥堵,数据接收到一半,客户端和服务端的连接突然中断,导致服务器接收不到客户端发过来的end 的消息。当接收不到end消息的时候,那处理该请求的对象,就会一直等待着,直到程序结束才会被释放。为了防止这种事情发生,我们还应该做一个请求计数,维护一个链表。当这个链表大于一定的数量(大于同时接收到请求的数量)时,将链表中最早的那个处理请求的对象给释放掉。

以下是改进后的代码

//mainwindow.cpp

QList<HandleRequest*> handleRequests;

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    http = new QHttpServer();
    connect(http, &QHttpServer::newRequest, this, &MainWindow::request);
    http->listen(QHostAddress::Any, 8087);
}

void MainWindow::request(QHttpRequest *req, QHttpResponse *resp)
{
    HandleRequest *handleRequest = new HandleRequest(req, resp, this);
    handleRequest->setHandleRequests(&handleRequests);
    handleRequests.append(handleRequest);

    if(handleRequests.count() > 50) {
        handleRequests.first()->deleteLater();
        handleRequests.pop_front();
    }
}

//handlerequest.cpp

HandleRequest::HandleRequest(QHttpRequest *req, QHttpResponse *resp, QObject *parent) :
    QObject(parent),
    m_req(req),
    m_resp(resp)
{
    m_req->storeBody();
    connect(m_req, &QHttpRequest::end, this, &HandleRequest::end);
}

void HandleRequest::end()
{
    QByteArray m_body = m_req->body();
    qDebug()<< m_body;

    m_resp->setHeader("Content-Length", QString::number(m_body.size()));
    m_resp->writeHead(200);
    m_resp->end(m_body);

    m_req->deleteLater();
    m_resp->deleteLater();
    m_req = nullptr;
    m_resp = nullptr;

    m_handleRequests->removeOne(this);
    this->deleteLater();
}

void HandleRequest::setHandleRequests(QList<HandleRequest *> *handleRequests)
{
    m_handleRequests = handleRequests;
}

源码1
源码2

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值