Tobias Hieta 09e7605b68 Use CXX_STANDARD 14 and centralize the setting to utils.cmake 8 years ago
..
3rdparty 63fb8b7ea0 Updated QHttp to 5433eb6 8 years ago
src 47f321c796 We don't want to export and import QHttp headers since we link against them. 8 years ago
CMakeLists.txt 09e7605b68 Use CXX_STANDARD 14 and centralize the setting to utils.cmake 8 years ago
LICENSE 4638151bfd WIP: qhttpserver->qhttp 8 years ago
README.md 4638151bfd WIP: qhttpserver->qhttp 8 years ago

README.md

QHttp

Table of contents

About

TOC

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++

Features

TOC

  • the only dependencies are: Qt 5, c++11 and joyent/http-parser

  • both TCP and UNIX (local) sockets are supported as backend.

  • separate namespaces 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.

Sample codes

TOC

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

Setup

TOC

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

Multi-threading

TOC

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:

Source tree

TOC

  • 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 makeing the library and holds all the .o, moc files, etc.

  • xbin/: all the executable and binaries will be placed on this folder by make.

Disclaimer

TOC

  • 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.

License

TOC

Distributed under the MIT license. Copyright (c) 2014, Amir Zamani.