Tobias Hieta 09e7605b68 Use CXX_STANDARD 14 and centralize the setting to utils.cmake | 8 tahun lalu | |
---|---|---|
.. | ||
3rdparty | 8 tahun lalu | |
src | 8 tahun lalu | |
CMakeLists.txt | 8 tahun lalu | |
LICENSE | 8 tahun lalu | |
README.md | 8 tahun lalu |
QHttp
is a lightweight, asynchronous and fast HTTP library, containing both server and client side classes for managing connections, parsing and building HTTP requests and responses.
this project is inspired by nikhilm/qhttpserver effort to implement a Qt HTTP server. QHttp
pushes the idea further by implementing client classes and better memory management, a lot more Node.js-like API, ...
the fantastic joyent/http-parser is the core parser of HTTP requests (server mode) and responses (client mode).
By using std::function
and c++11 lambda
, the API is intentionally similar to the Node.js' http module. Asynchronous and non-blocking HTTP programming is quite easy with QHttp
. have a look at sample codes.
the objective of QHttp
is being light weight with a simple API for Qt developers to implement RESTful web services in private (internal) zones. for a fast c++ Json parser / builder, have a look at azadkuh/gason++
the only dependencies are: Qt 5, c++11 and joyent/http-parser
both TCP and UNIX (local) sockets are supported as backend.
separate namespace
s for server and client classes.
HTTP server classes: QHttpServer, QHttpConnection, QHttpRequest and QHttpResponse.
HTTP client classes: QHttpClient, QHttpRequest and QHttpResponse.
automatic memory management of objects. Instances of connections, requests and replies will be deleted automatically when socket drops or disconnected.
PIMPL (Private classes) to achieve better ABI compatibility and cleaner API.
Asynchronous and non-blocking. You can handle thousands of concurrent HTTP connections efficiently by a single thread, although a multi-threaded HTTP server is easy to implement.
high throughput, I have tried the QHttp
and gason++ to implement a REST/Json web service on an Ubuntu VPS (dual core + 512MB ram) with more than 5800 connections per second (stress test). On a MacBook Pro (i5 4258U 4cores with HT + 8096MB ram), QHttp
easily reaches to more than 11700 connections / second. Generally QHttp
is 1.5x ~ 3x faster than Node.js
depending on your machine / OS. check benchmark app to measure your system.
Tested under Linux (Ubuntu 12.04 LTS, 14.04 LTS, g++) and OS X (10.9/10.10, clang) and Windows7 (msvc 2013). Easily portable where ever Qt 5 works. I have no Windows machine (nor time, nor interest), but this lib should work just fine under Windows, although I've not tested it by myself.
a HelloWorld HTTP server by QHttp
looks like:
int main(int argc, char** argv) {
QCoreApplication app(argc, argv);
using namespace qhttp::server;
QHttpServer server(&app);
// listening on 0.0.0.0:8080
server.listen(QHostAddress::Any, 8080, [](QHttpRequest* req, QHttpResponse* res) {
res->setStatusCode(qhttp::ESTATUS_OK); // status 200
res->addHeader("connection", "close"); // it's the default header, this line can be omitted.
res->end("Hello World!\n"); // response body data
// when "connection: close", the req and res will be deleted automatically.
});
if ( !server.isListening() ) {
fprintf(stderr, "failed. can not listen at port 8080!\n");
return -1;
}
// application's main event loop
return app.exec();
}
to request weather information by HTTP client:
int main(int argc, char** argv) {
QCoreApplication app(argc, argv);
using namespace qhttp::client;
QHttpClient client(&app);
QByteArray httpBody;
QUrl weatherUrl("http://api.openweathermap.org/data/2.5/weather?q=tehran,ir&units=metric&mode=xml");
client.request(qhttp::EHTTP_GET, weatherUrl, [&httpBody](QHttpResponse* res) {
// response handler, called when the HTTP headers of the response are ready
// gather HTTP response data
res->onData([&httpBody](const QByteArray& chunk) {
httpBody.append(chunk);
});
// called when all data in HTTP response have been read.
res->onEnd([&httpBody]() {
// print the XML body of the response
puts("\n[incoming response:]");
puts(httpBody.constData());
puts("\n\n");
QCoreApplication::instance()->quit();
});
// just for fun! print headers:
puts("\n[Headers:]");
const qhttp::THeaderHash& hs = res->headers();
for ( auto cit = hs.constBegin(); cit != hs.constEnd(); cit++) {
printf("%s : %s\n", cit.key().constData(), cit.value().constData());
}
});
return app.exec();
}
instructions:
# first clone this repository:
$> git clone --depth=1 https://github.com/azadkuh/qhttp.git -b master
$> cd qhttp
# prepare dependencies:
$> ./update-dependencies.sh
# now build the library and the examples
$> qmake qhttp.pro
$> make -j 8
As QHttp
is asynchrounous and non-bloking, your app can handle thousands of concurrent HTTP connections by a single thread.
in some rare scenarios you may want to use multiple handler threads (although it's not the best solution):
there are some blocking APIs (QSql, system calls, ...) in your connection handler (adopting asynchronous layer over the blocking API is a better approach).
the hardware has lots of free cores and the measurement shows that the load on the main QHttp
thread is close to highest limit. There you can spawn some other handler threads.
benchmark example shows how to implement a single or multi threaded HTTP app (both server and client). This example uses worker QThread
and QObject::moveToThread()
for worker objects. see aslo: Subclassing no longer recommended way of using QThread.
Note:
moving objects between threads is an expensive job, more ever the locking/unlocking mechanism, creating or stopping threads, ... cost even more! so using multiple threads in an application is not guaranteed to get better performance, but it's guaranteed to add more complexity, nasty bugs and headache!
see why other top performer networking libraries as ZeroMQ are concurrent but not multi-threaded by default:
3rdparty/
:
will contain http-parser
source tree as the only dependency.
this directory is created by setup. see also: setup.
example/
:
contains some sample applications representing the QHttp
usage:
helloworld/
:
the HelloWorld example of QHttp
, both server + client are represented.
see: README@helloworld
basic-server/
:
a basic HTTP server shows how to collect the request body, and respond to the clients.
see: README@basic-server
benchmark/
:
a simple utility to measure the throughput (requests per second) of QHttp
as a REST/Json server. this app provides both the server and attacking clinets.
see: README@benchmark
nodejs/
:
Node.js implementation of benchmark/
in server mode. Provided for benchmarking QHttp
with Node.js
as a RESTFul service app.
see: README@nodejs
src/
:
holds the source code of QHttp
. server classes are prefixed by qhttpserver*
and client classes by qhttpclient*
.
private/
:
Private classes of the library. see: d-pointers.tmp/
:
a temporary directory which is created while make
ing the library and holds all the .o
, moc files
, etc.
xbin/
:
all the executable and binaries will be placed on this folder by make
.
Implementing a lightweight and simple HTTP server/client in Qt with Node.js like API, is the main purpose of QHttp
.
There are lots of features in a full blown HTTP server which are out of scope of this small library, although those can be added on top of QHttp
.
The client classes are by no mean designed as a QNetworkAccessManager
replacement. QHttpClient
is simpler and lighter, for serious scenarios just use QNetworkAccessManager
.
I'm a busy person.
If you have any ideas, critiques, suggestions or whatever you want to call it, please open an issue. I'll be happy to hear from you what you'd see in this lib. I think about all suggestions, and I try to add those that make sense.
Distributed under the MIT license. Copyright (c) 2014, Amir Zamani.