关于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项目中使用。
无需编译成动态库,可以直接将其源码导入到自己的项目中,源码中有提供 .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
最终在项目中选择了第三种方案。