Skip to content

Commit

Permalink
update README and bump to version 3.0
Browse files Browse the repository at this point in the history
  • Loading branch information
azadkuh committed Jun 29, 2016
1 parent ca81e14 commit 286ced0
Showing 1 changed file with 111 additions and 105 deletions.
216 changes: 111 additions & 105 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,37 +14,50 @@
## About
[TOC](#table-of-contents)

`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](https://github.com/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 [nodejs/http-parser](https://github.com/nodejs/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](http://nodejs.org/api/http.html). Asynchronous and non-blocking HTTP programming is quite easy with `QHttp`. have a look at [sample codes](#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. [more](#disclaimer)


`QHttp` is a lightweight, asynchronous and fast HTTP library in `c++14 / Qt5`,
containing both server and client side classes for managing connections,
parsing and building HTTP requests and responses.

This project is inspired by
[nikhilm/qhttpserver](https://github.com/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 [nodejs/http-parser](https://github.com/nodejs/http-parser) is
the core parser of HTTP requests (server mode) and responses (client mode).
* By using `std::function` and `c++14 generic lambda`, the API is intentionally similar
to the [Node.js' http module](http://nodejs.org/api/http.html). Asynchronous
and non-blocking HTTP programming is quite easy with `QHttp`. have a look at
[sample codes](#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.
[more](#disclaimer)

> **attention**: c++14 is the minimum requirement for version 3.0+
> please see [releases](https://github.com/azadkuh/qhttp/releases)
## Sample codes
[TOC](#table-of-contents)

a HelloWorld **HTTP server** by `QHttp` looks like:
``` cpp
```cpp
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); // http status 200
//res->addHeader("connection", "close"); // optional, it's the default header
res->end("Hello World!\n"); // the response body data
// by "connection: close", the req and res objects will be deleted automatically.
server.listen( // listening on 0.0.0.0:8080
QHostAddress::Any, 8080,
[](QHttpRequest* req, QHttpResponse* res) {
// http status 200
res->setStatusCode(qhttp::ESTATUS_OK);
// the response body data
res->end("Hello World!\n");
// automatic memory management for req/res
});

if ( !server.isListening() ) {
fprintf(stderr, "failed. can not listen at port 8080!\n");
qDebug("failed to listen");
return -1;
}

Expand All @@ -58,9 +71,8 @@ int main(int argc, char** argv) {
QCoreApplication app(argc, argv);
using namespace qhttp::client;
QHttpClient client(&app);
QUrl weatherUrl("http://wttr.in/tehran");
QHttpClient client(&app);
QUrl weatherUrl("http://wttr.in/tehran");
client.request(qhttp::EHTTP_GET, weatherUrl, [](QHttpResponse* res) {
// response handler, called when the HTTP headers of the response are ready
Expand All @@ -72,21 +84,22 @@ int main(int argc, char** argv) {
res->onEnd([req]() {
// save req->collectedData() (as html body) to a file or ...
QCoreApplication::instance()->quit();
// done! now quit the application
qApp->quit();
});
// just for fun! print headers:
// just for fun! print incoming headers:
qDebug("\n[Headers:]");
const auto& hs = res->headers();
qhttp::for_each(hs.constBegin(), hs.constEnd(), [](auto cit){
qDebug("%s : %s", cit.key().constData(), cit.value().constData());
});
});
// set a timeout for making the request
// set a timeout for the http connection
client.setConnectingTimeOut(10000, []{
qDebug("connecting to HTTP server timed out!");
QCoreApplication::quit();
qApp->quit();
});
return app.exec();
Expand All @@ -97,25 +110,34 @@ int main(int argc, char** argv) {
## Features
[TOC](#table-of-contents)

* the only dependencies are: [Qt 5](http://qt-project.org/downloads), [c++11](http://en.wikipedia.org/wiki/C%2B%2B11) and [joyent/http-parser](https://github.com/joyent/http-parser)

* the only dependencies are: `Qt5`, `c++14` and the `http-parser`
* both TCP and UNIX (local) sockets are supported as backend.

* separate `namespace`s for server and client classes.

* HTTP server classes: [QHttpServer](./src/qhttpserver.hpp), [QHttpConnection](./src/qhttpserverconnection.hpp), [QHttpRequest](./src/qhttpserverrequest.hpp) and [QHttpResponse](./src/qhttpserverresponse.hpp).

* HTTP client classes: [QHttpClient](./src/qhttpclient.hpp), [QHttpRequest](./src/qhttpclientrequest.hpp) and [QHttpResponse](./src/qhttpclientresponse.hpp).

* **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++](https://github.com/azadkuh/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](./example/benchmard/README.md) to measure your system.

* Tested under **Linux** (Ubuntu 12.04 LTS, 14.04 LTS, g++) and **OS X** (10.9/10.10/10.11, clang). Easily portable where ever Qt 5 works. (tested by some users on Windows7/msvc2013 and Windows8.1/msvc2015)
* HTTP server classes: [QHttpServer](./src/qhttpserver.hpp),
[QHttpConnection](./src/qhttpserverconnection.hpp),
[QHttpRequest](./src/qhttpserverrequest.hpp) and
[QHttpResponse](./src/qhttpserverresponse.hpp).
* HTTP client classes: [QHttpClient](./src/qhttpclient.hpp),
[QHttpRequest](./src/qhttpclientrequest.hpp) and
[QHttpResponse](./src/qhttpclientresponse.hpp).
* **automatic memory management** of objects. Instances of connections,
requests and replies will be deleted automatically when socket drops or
*disconnected*.
* **PIMPL** (Private implementaion) to achieve better ABI compatibility and cleaner
API and faster compile time.
* **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++](https://github.com/azadkuh/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, 8GB 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.
* Easily portable where ever `Qt5 / c++14` works. Tested under:
- **Linux** Ubuntu 12.04 ~ 16.04 LTS, g++ 5.3+
- **OS X** 10.9+, clang 3.7+
- **Windows**, msvs2015 / mingw


## Setup
Expand All @@ -124,95 +146,79 @@ int main(int argc, char** argv) {
instructions:
```bash
# first clone this repository:
$> git clone --depth=1 https://github.com/azadkuh/qhttp.git -b master
$> git clone https://github.com/azadkuh/qhttp.git
$> cd qhttp

# prepare dependencies:
$> ./update-dependencies.sh
$qhttp/> ./update-dependencies.sh

# now build the library and the examples
$> qmake qhttp.pro
$> make -j 8
$qhttp/> qmake -r qhttp.pro
$qhttp/> make -j 8
```

## Multi-threading
[TOC](#table-of-contents)

As `QHttp` is **asynchronous** and **non-blocking**, 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):
As `QHttp` is **asynchronous** and **non-blocking**, your app can handle
thousands of concurrent HTTP connections by a single thread.

* there are some blocking APIs (QSql, system calls, ...) in your connection handler (adopting asynchronous layer over the blocking API is a better approach).
in some rare scenarios you may want to use multiple handler threads (although
it's not the best solution):

* 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](./example/benchmark/README.md) 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 also: [Subclassing no longer recommended way of using QThread](http://qt-project.org/doc/note_revisions/5/8/view).

**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:

* [ZeroMQ : Multithreading Magic](http://zeromq.org/blog:multithreading-magic)
* [Node.js : about](http://nodejs.org/about/)
* 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.


## Source tree
[TOC](#table-of-contents)


* **`3rdparty/`**:
will contain `http-parser` source tree as the only dependency.
this directory is created by setup. see also: [setup](#setup).

* **`example/`**:
contains some sample applications representing the `QHttp` usage:
* **`helloworld/`**:
the HelloWorld example of `QHttp`, both server + client are represented.
see: [README@helloworld](./example/helloworld/README.md)

* **`basic-server/`**:
a basic HTTP server shows how to collect the request body, and respond to the clients.
see: [README@basic-server](./example/basic-server/README.md)


* **`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 clients.
see: [README@benchmark](./example/benchmark/README.md)

* **`nodejs/`**:
Node.js implementation of `benchmark/` in server mode. Provided for benchmarking `QHttp` with `Node.js` as a RESTFul service app.
see: [README@nodejs](./example/nodejs/README.md)


* **`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](https://qt-project.org/wiki/Dpointer).

* **`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`.

- **`src/`**: holds the source code of `QHttp`. server classes are prefixed by
`qhttpserver*` and client classes by `qhttpclient*`.
- **`private/`**: Private classes of the library.
- **`3rdparty/`**: will contain `http-parser` source tree as the only
dependency. this directory is created by setup. see also: [setup](#setup).
- **`example/`**: contains some sample applications representing the `QHttp`
usage:
- **`helloworld/`**: the HelloWorld example of `QHttp`, both server + client
are represented. see: [README@helloworld](./example/helloworld/README.md)
- **`basic-server/`**: a basic HTTP server shows how to collect the request
body, and respond to the clients. see:
[README@basic-server](./example/basic-server/README.md)
- **`keep-alive`**: shows how to keep an http connection open and
transmitting many requests/responses. see:
[README@keep-alive](./example/keep-alive/README.md)
- **`post-collector`**: another server example shows how to collect large
data by POST requests. see:
[README@post-collector](./example/postcollector/README.md)
- **`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 libraries will be placed on this folder by
build system.



## Disclaimer
[TOC](#table-of-contents)

* 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.
- 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` which supports proxy, redirections, ...
- 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.
> If you have any ideas, critiques, suggestions or whatever you want to call
> it, please open an issue. I'll be happy to hear different ideas, will think
> about them, and I try to add those that make sense.

## License
Expand Down

0 comments on commit 286ced0

Please sign in to comment.