GithubHelp home page GithubHelp logo

jqhttpserver's Introduction

介绍

JQHttpServer是基于Qt开发的轻量级HTTP/HTTPS服务器

底层有QTcpSocket、QSslSocket两个版本,分别对应HTTP和HTTPS。

用到的Qt库有:

  • core
  • network
  • concurrent
  • testlib(测试用,运行不需要)
  • OpenSSL(如果需要HTTPS)

不依赖外部库,理论上可以部署到任何Qt支持的平台上。

推荐使用Linux系统或者Unix系统,因为在5.7后,Qt更换了Unix相关系统的底层模型,从select更换为了poll,这样改进后,并发就脱离了1024个的限制。

使用本库,推荐 Qt5.8.0 或者更高版本,以及支持 C++11 的编译器(例如VS2013或者更高),对操作系统无要求。

本库源码均已开源在了GitHub上。

GitHub地址:https://github.com/188080501/JQHttpServer

方便的话,帮我点个星星,或者反馈一下使用意见,这是对我莫大的帮助。

若你遇到问题、有了更好的建议或者想要一些新功能,都可以直接在GitHub上提交Issues:https://github.com/188080501/JQHttpServer/issues

性能介绍

本库性能一般,符合一般项目使用标准

原因是Qt底层是poll,库中又有一些跨线程操作

在我的电脑( MacBookPro 16" & i9 CPU & macOS 10.15.7 )使用siege进行测试,命令行参数如下:

siege -c 2 -r 5000 http://127.0.0.1:23412

结果如下:

{	"transactions":			       10000,
	"availability":			      100.00,
	"elapsed_time":			        1.24,
	"data_transferred":		        0.10,
	"response_time":		        0.00,
	"transaction_rate":		     8064.52,
	"throughput":			        0.08,
	"concurrency":			        1.90,
	"successful_transactions":	       10000,
	"failed_transactions":		           0,
	"longest_transaction":		        0.35,
	"shortest_transaction":		        0.00
}

即QPS 8064

License

See the LICENSE file for license rights and limitations (MIT).

jqhttpserver's People

Contributors

188080501 avatar codegatling avatar drop1et avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

jqhttpserver's Issues

静态路由使用不便

现在使用静态路由要自行实现 sessionAccepted 函数,颇为不便,建议增加专用的静态路由功能

80端口启动失败

为什么我是用80 端口 listen的时候失败了,8080 可以成功,然后查看了80 端口没有别的应该占用。
我是uos统信 个人版20 。是系统原因吗?
image
image

Error SSL while running HttpsServerDemo

When starting the application "HttpsServerDemo", i got this error:
qt.network.ssl: QSslSocket: cannot resolve TLSv1_1_client_method
qt.network.ssl: QSslSocket: cannot resolve TLSv1_2_client_method
qt.network.ssl: QSslSocket: cannot resolve TLSv1_1_server_method
qt.network.ssl: QSslSocket: cannot resolve TLSv1_2_server_method
qt.network.ssl: QSslSocket: cannot resolve SSL_select_next_proto
qt.network.ssl: QSslSocket: cannot resolve SSL_CTX_set_next_proto_select_cb
qt.network.ssl: QSslSocket: cannot resolve SSL_get0_next_proto_negotiated
qt.network.ssl: QSslSocket: cannot resolve SSL_set_alpn_protos
qt.network.ssl: QSslSocket: cannot resolve SSL_CTX_set_alpn_select_cb
qt.network.ssl: QSslSocket: cannot resolve SSL_get0_alpn_selected
sslCertificate: QSslCertificate("1", "ae:01:71:c8:21:fc:00:c2", "eKXBjkCzjZbWnEvw5NXsWw==", ("Internet Widgits Pty Ltd"), ("Internet Widgits Pty Ltd"), QMap(), QDateTime(2017-04-09 07:07:27.000 UTC Qt::TimeSpec(UTC)), QDateTime(2027-04-07 07:07:27.000 UTC Qt::TimeSpec(UTC)))
sslKey: QSslKey(PrivateKey, RSA, 2048)
caCertificates: ()
listen: true

And when i send packet data to the server, the server got error like this:
qt.network.ssl: QSslSocket: cannot call unresolved function TLSv1_2_server_method
qt.network.ssl: QSslSocket: cannot call unresolved function TLSv1_2_server_method

could you help me, why this happens ?

长连接时后续请求会被忽略

我在使用 jmeter 多线程测试多个接口时,发现如果都勾选了 keep-alive,每个线程第一个请求之后的请求都会失败。
我看到 JQHttpServer::Session 里有个 30秒 的计时器,推测这个库应该有支持 Http/1.1 的长连接功能。
检查了下代码,发现是由于在 JQHttpServer::Session::onBytesWritten 函数里,大约第826行,调用了 socket_->disconnectFromHost() 关掉了该连接,导致后续请求都不会被接收。
建议 session 增加一个 reset 函数,在一个请求结束后(比如 第826行 的 回复完成后),将 session 的解析参数重置为默认值,以继续解析后续请求。

win10和ubuntu 16.04下性能测试问题,每个请求20ms

你好,我在win10和ubuntu 16.04下进行性能测试(Qt5.7),发现单次请求、响应时间延迟非常大,每个请求20ms左右。

测试方法为:在同一台电脑上先启动HttpServerDemo,然后运行HttpClientDemo,在client端发起5000次请求(单线程,即在main线程内),方法同benchMarkFor5000,并计算时间。测试过程中,两个进程的cpu利用率以及系统cpu利用率都很低。

折算下来,空跑QPS才50,请问这可能是什么原因导致性能上不去?

探讨是否可以有 QML 接口

在 readme 中提及了并发数的问题。

推荐使用Linux系统或者Unix系统,因为在5.7后,Qt更换了Unix相关系统的底层模型,从select更换为了poll,这样子网络库的并发就脱离了1024个的限制。

看起来应该可以应用方向是小型,实用上。

这里我想探讨一下是否可以有 QML 的接口。或者说 QML 的接口该如何设计呢?

AbstractManage 中的 QMutex 互斥锁是否必要?

我发现在 AbstractManage::newSession 中,使用了 QMutex 对 availableSessions_ 进行了保护,但是这种保护是否必要?

  1. 所有的 Session 对象均在同一个线程(serverThreadPool_ 中的唯一一个线程)。
  2. 根据我的测试,Lambda 槽函数调用时是非跨线程的。
  3. 我没有找到其他的跨线程的对 availableSessions_ 的访问。
    所以应当不会有多线程冲突。
    另外,设置 availableSessions_ 的用途是什么?

QT5.15.0中对于API的变更

在Qt5.15.0(Ubuntu20.04自编译)环境下,发现使用JQNet.cpp会提示

‘void QNetworkReply::error(QNetworkReply::NetworkError)’ is deprecated: Use QNetworkReply::errorOccurred(QNetworkReply::NetworkError) instead

看起来是有一些API变更了呢

附带错误提示全文:

../H2server/library/JQLibrary/src/JQNet.cpp: In member function ‘void JQNet::HTTP::handle(QNetworkReply*, const int&, const std::function<void(const QList<QPair<QByteArray, QByteArray> >&, const QByteArray&)>&, const std::function<void(const QList<QPair<QByteArray, QByteArray> >&, const QNetworkReply::NetworkError&, const QByteArray&)>&, const std::function<void()>&)’:
../H2server/library/JQLibrary/src/JQNet.cpp:682:124: warning: ‘void QNetworkReply::error(QNetworkReply::NetworkError)’ is deprecated: Use QNetworkReply::errorOccurred(QNetworkReply::NetworkError) instead [-Wdeprecated-declarations]
  682 |     QObject::connect( reply, static_cast< void( QNetworkReply::* )( QNetworkReply::NetworkError ) >( &QNetworkReply::error ), [ reply, timer, onError, isCalled ](const QNetworkReply::NetworkError &code)
      |                                                                                                                            ^
In file included from /opt/qt5.15.0/include/QtNetwork/QNetworkReply:1,
                 from ../H2server/library/JQLibrary/include/JQNet.h:31,
                 from ../H2server/library/JQLibrary/src/JQNet.cpp:18:
/opt/qt5.15.0/include/QtNetwork/qnetworkreply.h:161:10: note: declared here
  161 |     void error(QNetworkReply::NetworkError);
      |          ^~~~~
../H2server/library/JQLibrary/src/JQNet.cpp:682:124: warning: ‘void QNetworkReply::error(QNetworkReply::NetworkError)’ is deprecated: Use QNetworkReply::errorOccurred(QNetworkReply::NetworkError) instead [-Wdeprecated-declarations]
  682 |     QObject::connect( reply, static_cast< void( QNetworkReply::* )( QNetworkReply::NetworkError ) >( &QNetworkReply::error ), [ reply, timer, onError, isCalled ](const QNetworkReply::NetworkError &code)
      |                                                                                                                            ^
In file included from /opt/qt5.15.0/include/QtNetwork/QNetworkReply:1,
                 from ../H2server/library/JQLibrary/include/JQNet.h:31,
                 from ../H2server/library/JQLibrary/src/JQNet.cpp:18:
/opt/qt5.15.0/include/QtNetwork/qnetworkreply.h:161:10: note: declared here
  161 |     void error(QNetworkReply::NetworkError);
      |          ^~~~~

长时间多次post请求会出现内存泄露?

包含头文件,然后客户端使用示例代码:
const auto &&reply = JQNet::HTTP::post( "http://127.0.0.1:23412/TestUrl", "AppendData" );
进行120ms/次请求,则出现内存不断增长的问题,请问这个问题有什么好的解决方案吗?
服务端正常,客户端出现内存泄露?期待你的交流,我的QQ4589968

Server收不到请求

您好,我测试server的回调函数,只能放在mian函数中,否则就无法收不到请求

如何在session中返回一个自定义的错误?

你好,感谢上一次的回复建议。
这里请教一个问题:就是如何在session中返回一个自定义错误?
代码:

static JQHttpServer::TcpServerManage httpServer( maxThreads ); // 设置最大处理线程数,默认2个
httpServer.setHttpAcceptedCallback( std::bind(onHttpAccepted, std::placeholders::_1 ) );

设置了onHttpAccepted 回调函数,同时在Session 中增加了一个自定义错误代码 internalErrorCode_,
通过如下代码暴露出来:
int JQHttpServer::Session::internalErrorCode() const
{
// JQHTTPSERVER_SESSION_PROTECTION( "internalErrorCode", 0 )

return internalErrorCode_;

}

在session的 replyImage中修改internalErrorCode_,该值在回调函数中不能获得(修改没起作用),是不是哪里有问题 ?
尝试修改:
int JQHttpServer::Session::replyHttpCode() const
中的 replyHttpCode返回,也没有效果,不知是哪里问题?请教!

在次感谢!

server端程序运行崩溃

在CPU负载较高,或回调执行时间较长下,程序可能崩溃。
看了下代码,回调是在另一个线程下运行,当调用session->reply时,session,iodeviece_都有可能随时被删除(如超时);
另外,如果客户端提前超时,关闭连接,那么服务端对accept的TcpSocket未做处理,这种场景下程序运行行为如何,是否导致ioDevice_指向已销毁的socket资源。

compile this part in qt 5.2, many errors,

library/JQLibrary/src/JQHttpServer.cpp: In member function ‘bool JQHttpServer::AbstractManage::startServerThread()’:
library/JQLibrary/src/JQHttpServer.cpp:804:7: error: no matching function for call to ‘run(QThreadPool*, JQHttpServer::AbstractManage::startServerThread()::<lambda()>)’
} );
^
In file included from /usr/include/qt5/QtConcurrent/QtConcurrent:14:0,
from library/JQLibrary/src/JQHttpServer.cpp:34:
/usr/include/qt5/QtConcurrent/qtconcurrentrun.h:70:12: note: candidate: template QFuture QtConcurrent::run(T (*)())
QFuture run(T (functionPointer)())
^~~
/usr/include/qt5/QtConcurrent/qtconcurrentrun.h:70:12: note: template argument deduction/substitution failed:
library/JQLibrary/src/JQHttpServer.cpp:804:7: note: mismatched types ‘T()’ and ‘QThreadPool’
} );
^
In file included from /usr/include/qt5/QtConcurrent/QtConcurrent:14:0,
from library/JQLibrary/src/JQHttpServer.cpp:34:
/usr/include/qt5/QtConcurrent/qtconcurrentrun.h:75:12: note: candidate: template<class T, class Param1, class Arg1> QFuture QtConcurrent::run(T (
)(Param1), const Arg1&)
QFuture run(T (*functionPointer)(Param1), const Arg1 &arg1)
^~~

failed in compiling with qtcreator

Hello!Thank you for sharing your code firstly!
I want to use your server to test my client,however it was failed when I compiled your code.The error info is as follows.Could you help me to fix this problem?Thank you again.

/home/xue/JQHttpServer/JQHttpServer/library/JQLibrary/src/JQNet.cpp:281: error: conversion from 'const QByteArray' to 'QIODevice*' is ambiguous
     auto reply = manage_.sendCustomRequest( request, "PATCH", appendData );
/home/xue/JQHttpServer/JQHttpServer/library/JQLibrary/src/JQNet.cpp:315: error: conversion from 'const QByteArray' to 'QIODevice*' is ambiguous
     auto reply = manage_.sendCustomRequest( request, "PATCH", appendData );
                                                                          

JQHttpServer浏览器请求的时候如何返回一个本地的html页面

比如浏览器访问:http://localhost:23412/index

服务器收到index后我想返回一个本地已经写好的html页面,以下是demo中的例子:
session->replyText( QString( "url:%1\nbody:%2" ).arg( session->requestUrl(), QString( session->requestBody() ) ) );
session->replyRedirects( QUrl( "http://www.baidu.com" ) );
session->replyJsonObject( { { { "message", "ok测试部" } } } );
session->replyJsonArray( { "a", "b", "c" } );
session->replyFile( "/Users/jason/Desktop/Test1.Test2" );
session->replyImage( QImage( "/Users/jason/Desktop/Test.png" ) );
session->replyBytes(QByteArray(4,'\x24'));

看到请解释下,非常感谢

跨域

请问C++服务端这边如何支持跨域

HttpServer接收回调问题

您好,还是原来那个问题,我在linux(Ubuntu18.04)qt(5.14.1)下也测试过。使用lambda函数,好像只能在mian函数内,客户端请求才能收到,一但在不在,客户端请求接收不到,返回false。还请帮忙看看 int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.setWindowTitle("HttpServer");
w.show();
#if 1
JQHttpServer::TcpServerManage tcpServerManage(10); // 设置最大处理线程数,默认2个
tcpServerManage.setHttpAcceptedCallback(
[]( const QPointer< JQHttpServer::Session > &session )
{
// 回调发生在新的线程内,不是主线程,请注意线程安全
// 若阻塞了此回调,那么新的连接将不会得到处理(默认情况下有2个线程可以阻塞2次,第3个连接将不会被处理)
qDebug() << "请求来源IP: "+session->requestSourceIp(); //请求来源IP
qDebug() << "url:"+session->requestUrl(); //url 后面参数
qDebug() << "请求方式: "+session->requestMethod(); //POST GET
qDebug() << "postdata: "+session->requestBody();
QByteArray postdata = session->requestBody();
QString ssize = QString::number(postdata.size(),10);
qDebug() << "postdata.size: "+ssize;
session->replyText( QString( "url:%1\nbody:%2" ).arg( session->requestUrl(), QString( session->requestBody() ) ) );
// 注1:因为一个session对应一个单一的HTTP请求,所以session只能reply一次
// 注2:在reply后,session的生命周期不可控,所以reply后不要再调用session的接口了
} );
qDebug() << "listen:" << tcpServerManage.listen( QHostAddress("192.168.124.128"), 9091);
qDebug() << ("Http服务已启动");
#endif
return a.exec();`

image
image
image

关于服务端主动下发的问题

您好,我想请问一下,我要实现服务端能主动下发,也就是长连接,我测试每次请求都会有新的连接过来,这时候我保留套接字,然后重新new一个session 来应答,这样是否可行?

要怎么实现get body部分

put post都可以“const QByteArray &body”,但是get不行,请教大神帮忙解答下。要怎么实现body

SSL Error

When i run this JQHttpServer using my valid ssl certification with digicert cert, Got error from third party enggine : "SSL routines:tls_process_server_certificate:certificate verify failed". And also got error message from the application : "JQHttpServer::Session::inspectionBuffer: error3: HEAD". Could you help me to solve this problem?

Thank you.

关于遇到超时的问题

你好我使用 您的库 请求 http 有时会发现 就算外网 不可请求到 也是一直阻塞直到超时 才返回 是否可以 立即返回

用于地图瓦片数据的发布中的优化建议(tms)

Hi 188080501
我用JQHttp 发布地图瓦片数据,使用稳定。希望增加一个针对地图数据特点的 replyTmsImage,对地图数据进行预读与缓存,提高地图数据的相应速度。TMS格式的地图瓦片数据访问有一定的规律,简单说就是将当前访问的图片文件的前后图片预读,或者使用进行缓存,缓存数量可以通过参数设定。谢谢!

访问一次会有两次处理

用浏览器访问一次,服务器显示处理了两次
第一次为正常请求
Body ""
Header QMap(("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,/;q=0.8")("Accept-Encoding", "gzip, deflate")("Accept-Language", "zh-CN,en-US;q=0.8")("Cache-Control", "max-age=0")("Connection", "keep-alive")("Host", "191.167.2.36:23412")("Upgrade-Insecure-Requests", "1")("User-Agent", "Mozilla/5.0 (Linux; Android 7.1.1; 1801-A01 Build/NMF26X; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/59.0.3071.82 Mobile Safari/537.36")("X-Requested-With", "org.qtproject.example.minibrowser"))
Method "GET"
UrlPath ""
Url "/"
UrlQuery QMap()
UrlPathSplitToList ()
第二次为/favicon 请求打印出来如下
Body ""
Header QMap(("Accept", "image/webp,image/apng,image/,/*;q=0.8")("Accept-Encoding", "gzip, deflate")("Accept-Language", "zh-CN,en-US;q=0.8")("Connection", "keep-alive")("Host", "191.167.2.36:23412")("Referer", "http://191.167.2.36:23412/")("User-Agent", "Mozilla/5.0 (Linux; Android 7.1.1; 1801-A01 Build/NMF26X; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/59.0.3071.82 Mobile Safari/537.36")("X-Requested-With", "org.qtproject.example.minibrowser"))
Method "GET"
UrlPath "/favicon.ico"
Url "/favicon.ico"
UrlQuery QMap()
UrlPathSplitToList ("favicon.ico")

不知道为什么会有两次

希望能为replyBytes增加MimeType的选项

如题,因为对于部分网页应用而言,Content-Type的类型是必须的。(如模块化加载JavaScript和图片显示)
这也可以简化对于小型HTTP服务获取文件类型的判断
我目前更改了一下replyBytes的接口,如下:

static QString replyBytesFormat(
        "HTTP/1.1 %1 OK\r\n"
        "Content-Type: %2\r\n"
        "Content-Length: %3\r\n"
        "Access-Control-Allow-Origin: *\r\n"
        "Access-Control-Allow-Headers: Content-Type,X-Requested-With\r\n"
        "\r\n"
    );
void JQHttpServer::Session::replyBytes(const QByteArray &bytes, const int &httpStatusCode,const QString mime)
{
    JQHTTPSERVER_SESSION_REPLY_PROTECTION( "replyBytes" )

    if ( QThread::currentThread() != this->thread( ))
    {
        replyHttpCode_ = httpStatusCode;

        QMetaObject::invokeMethod(this, "replyBytes", Qt::QueuedConnection, Q_ARG(QByteArray, bytes), Q_ARG(int, httpStatusCode), Q_ARG(QString, mime));
        return;
    }

    JQHTTPSERVER_SESSION_REPLY_PROTECTION2( "replyBytes" )

    auto buffer = new QBuffer;
    buffer->setData( bytes );

    if ( !buffer->open( QIODevice::ReadWrite ) )
    {
        qDebug() << "JQHttpServer::Session::replyBytes: open buffer error";
        delete buffer;
        this->deleteLater();
        return;
    }

    ioDeviceForReply_.reset( buffer );
    ioDeviceForReply_->seek( 0 );

    replyBodySize_ = buffer->buffer().size();

    const auto &&data = replyBytesFormat.arg(
                QString::number( httpStatusCode ),
                mime,
                QString::number( replyBodySize_ )
            ).toUtf8();

    waitWrittenByteCount_ = data.size() + buffer->buffer().size();
    ioDevice_->write(data);
}

这样在返回HTTP回复的时候就可以设置Content-Type了

如何在回调中调用数据库

你好,你这个轻量级http服务器很不错。不够头疼的是5.12以后,在回调中调用数据库一直失败,请问有什么好的方法在收到http请求时调用数据库吗

Service

请问Service模块的作用是什么?

解析提交的表单数据头

请教一下,用这个server,如何解析提交的文件和键值混和表单数据,主要不知道如何解析出请求头的文件名称

关于html页面显示图片的问题

我有一个需求是服务器同时返回一段文本和一张图片。
我尝试过的方法:
1、在setHttpAcceptedCallback回调中同时调用
{
session->replyText(...)
session->replyImage(...)
}
这样会出现 服务器程序停止运行

2、我用session->replyFile 函数返回一个html 文件

(代码格式是故意少写了<,不然该页面不能显示)
html>
body >
img src ="http://www.baidu.com/img/bd_logo1.png" />
img src ="http://192.168.31.101:23412/bb.png"/>
/body>
/html>

第一张百度图片显示正常。
第二张图片是我服务器上的图片,不能正常显示。

请问是否我图片路径有问题,通过html方法如何访问我的服务器图片

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.