WHCSRL 技术网

关于C++ Qt项目实现最简单Http Server的踩坑记录

前言

在开发Qt项目中,需要实现一个Http服务器功能,接收并处理客户端的http请求,Qt的发行版中并没有提供相应的类来处理,所以要实现该功能只能找其他开源项目了,本文主要记录我在收集相关资料过程中踩过的坑,希望能给需要的人提供一点帮助。

qthttpserver

前面说到,Qt官方在发行版中并没有提供相应的类来实现HTTP 服务端,但是Qt-lab中提供了一个qthttpserver,Github地址在这里,不知道基于什么原因Qt官方没有将其纳入正式的Qt发行版中,如果要使用qthttpserver的话,就得自己下载源码进行编译了,不过编译可没那么容易,会遇到各种错误,而且还没有提供说明文档,这就不太友好了。由于时间紧迫,折腾一番之后决定采用别的方法,感兴趣的可以去研究一番。

cpp-httplib

这是Github上一个开源的C++实现http server的项目,使用方法非常简单,就只有一个头文件,引入到自己的项目中就可以使用了,不过这是一个多线程“阻塞”HTTP 库,如果您正在寻找“非阻塞”库,那就要换别的了。具体使用可以参考Github里面的文档介绍,很详细。Github地址在这里

但是,在实际体验的过程中发现一个问题,先看它提供的简单demo,server端,接收客户端的post请求:

#define CPPHTTPLIB_OPENSSL_SUPPORT
#include "path/to/httplib.h"

// HTTP
httplib::Server svr;

// HTTPS
httplib::SSLServer svr;

svr.Post("/hello", [](const httplib::Request &, httplib::Response &res) {
   //处理接收的消息
   //to do...
   //并返回数据给客户端
  res.set_content("this is post server reply.", "text/plain");
});

svr.listen("0.0.0.0", 8080);

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

在svr.Post参数中的lambda函数中会收到客户端post发送的数据,并在这里返回数据给客户端,这里是在子线程中的,我在Qt项目中,想在此处发信号出来通知主线程去处理别的事情,发完信号后,主线程不能用异步的方式(Qt::QueuedConnection)连接 该信号,只能用直连(Qt::DirectConnection),这样就带来一个问题,无法与主线程通信了,如果需要更新UI等操作,就没法进行。

经过综合考量,最终还是放弃了这个开源库的使用。

QtWebApp

QtWepApp 是 C++ 中的 HTTP 服务器库,适用于 Linux、Windows、Mac OS 和Qt 框架支持的许多其他操作系统。

这个库使用也非常简单,而且可以支持Qt框架,所以比较适合在Qt项目中使用。

官网介绍在这里

Github地址在这里

无需编译成动态库,可以直接将其源码导入到自己的项目中,源码中有提供 .pri文件,在工程文件中导入就可以了。
在这里插入图片描述
简单使用:

// 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>");
}

// 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();
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

具体使用方法可以参照提供的两个demo。

它提供了通过配置文件来设置相关参数,上面的代码是读取本地配置文件,也可以在代码中进行配置

m_pSettings=new QSettings(QSettings::UserScope,this);
 m_pSettings->setValue("port",port);
 m_pSettings->setValue("minThreads","1"); 
 m_pSettings->setValue("maxThreads","2");
 m_pSettings->setValue("cleanupInterval","60000");
 m_pSettings->setValue("readTimeout","60000");
 m_pSettings->setValue("maxRequestSize","16000");
 m_pSettings->setValue("maxMultiPartSize","10000000");
 m_pSettings->sync();

 m_pRequestHander = new RequestHandler(this);
new HttpListener(m_pSettings,m_pRequestHander,this);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

需要注意的是,用QSettings需要先设置,否则QSettings不能生效

QCoreApplication::setOrganizationName("xxx");
QCoreApplication::setApplicationName("xxx");
  • 1
  • 2

最终在项目中选择了第三种方案。

推荐阅读