diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a6fb78b --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +build-libs/ diff --git a/Readme.md b/Readme.md index 771f44b..f289ee1 100644 --- a/Readme.md +++ b/Readme.md @@ -22,6 +22,7 @@ There are several implementations of HTTP server: - C++ : [cpprestsdk](https://github.com/Microsoft/cpprestsdk) - C++ : [restbed](https://github.com/corvusoft/restbed) - C++ : [pistache](https://github.com/oktal/pistache) +- C++ : [poco](https://github.com/pocoproject/poco) - PHP : Native implementation # Benchmark @@ -84,6 +85,24 @@ Benchmark was done by running `ab -n 1000 -c 1 -k ` (see [Apache Benchmark] (-) Unit tests are ill-formed. +## POCO + +#### Benchmark results for default JSON implementation on Linux + +![poco benchmark results](https://github.com/sineang01/cpp-rest-frameworks-benchmark/blob/master/results/benchmark-poco-default_json_impl.png) + +#### Benchmark results with RapidJSON on Linux + +![poco benchmark results](https://github.com/sineang01/cpp-rest-frameworks-benchmark/blob/master/results/benchmark-poco-rapidjson.png) + +(+) POCO has its own implementation of JSON serializer/deserializer, so you don't need to additionally include RapidJSON or other library, however the default implementation is much slower than the one using RapidJSON. + +(+) Inline code documentation. + +(-) No comprehensive list of implemented features. + +(+) Licensed under Boost software License. + ## PHP native implementation ![PHP native implementation benchmark results](https://raw.githubusercontent.com/metamaker/cpp-rest-frameworks-benchmark/master/results/benchmark-php.png) diff --git a/bootstrap.sh b/bootstrap.sh old mode 100644 new mode 100755 index 109cfd4..c18acaa --- a/bootstrap.sh +++ b/bootstrap.sh @@ -10,7 +10,7 @@ EOF # Install build tools and ntp (to prevent clock skewing) -sudo mkdir /tmp/build-libs +mkdir build-libs sudo apt-get install -y --allow-downgrades --allow-remove-essential --allow-change-held-packages ntp cmake # Replace nginx configuration @@ -54,36 +54,51 @@ EOF sudo apt-get install -y --allow-downgrades --allow-remove-essential --allow-change-held-packages libcpprest-dev # Install RapidJSON library -# RapidJSON is required for pistache and restbed samples to produce JSON result +# RapidJSON is required for pistache, restbed and POCO samples to produce JSON result -cd /tmp/build-libs -git clone https://github.com/miloyip/rapidjson -cd rapidjson +pushd build-libs + +git clone https://github.com/Tencent/rapidjson.git +pushd rapidjson git submodule update --init cmake -DCMAKE_BUILD_TYPE=Release . -make +make -j 8 sudo make install +popd # Install Pistache C++ REST framework -cd /tmp/build-libs git clone https://github.com/oktal/pistache.git -cd pistache +pushd pistache git submodule update --init cmake -DCMAKE_BUILD_TYPE=Release . -make +make -j 8 sudo make install +popd # Install Restbed C++ REST framework -cd /tmp/build-libs git clone --recursive https://github.com/corvusoft/restbed.git -cd restbed +pushd restbed cmake -DCMAKE_BUILD_TYPE=Release . -make +make -j 8 sudo make install sudo cp -r distribution/library/* /usr/lib/ sudo cp -r distribution/include/* /usr/include/ +popd + +# Install POCO C++ framework + +git clone https://github.com/pocoproject/poco.git +pushd poco +mkdir cmake_build +cd cmake_build +cmake -DCMAKE_BUILD_TYPE=Release .. +make -j 8 +sudo make install +popd + +popd cat << EOF |-----------------------------------| @@ -93,18 +108,37 @@ cat << EOF |-----------------------------------| EOF -cd /vagrant/cpp/cpprestsdk-default_json_impl +pushd samples/cpp + +pushd cpprestsdk-default_json_impl cmake -DCMAKE_BUILD_TYPE=Release . -make +make -j 8 +popd -cd /vagrant/cpp/cpprestsdk-rapidjson +pushd cpprestsdk-rapidjson cmake -DCMAKE_BUILD_TYPE=Release . -make +make -j 8 +popd -cd /vagrant/cpp/pistache +pushd pistache cmake -DCMAKE_BUILD_TYPE=Release . -make +make -j 8 +popd -cd /vagrant/cpp/restbed +pushd restbed cmake -DCMAKE_BUILD_TYPE=Release . -make +make -j 8 +popd + +pushd poco-default_json_impl +cmake -DCMAKE_BUILD_TYPE=Release . +make -j 8 +popd + +pushd poco-rapidjson +cmake -DCMAKE_BUILD_TYPE=Release . +make -j 8 +popd + +popd + diff --git a/results/benchmark-poco-default_json_impl.png b/results/benchmark-poco-default_json_impl.png new file mode 100644 index 0000000..30295f5 Binary files /dev/null and b/results/benchmark-poco-default_json_impl.png differ diff --git a/results/benchmark-poco-rapidjson.png b/results/benchmark-poco-rapidjson.png new file mode 100644 index 0000000..a513da4 Binary files /dev/null and b/results/benchmark-poco-rapidjson.png differ diff --git a/samples/cpp/poco-default_json_impl/CMakeLists.txt b/samples/cpp/poco-default_json_impl/CMakeLists.txt new file mode 100644 index 0000000..2cd19a0 --- /dev/null +++ b/samples/cpp/poco-default_json_impl/CMakeLists.txt @@ -0,0 +1,12 @@ +cmake_minimum_required(VERSION 3.5) +project(main) + +find_package(Poco REQUIRED COMPONENTS Foundation Net JSON Util) + +add_executable(main main.cpp) +target_link_libraries(main + Poco::Foundation + Poco::Net + Poco::JSON + Poco::Util +) diff --git a/samples/cpp/poco-default_json_impl/main.cpp b/samples/cpp/poco-default_json_impl/main.cpp new file mode 100644 index 0000000..5f99b0f --- /dev/null +++ b/samples/cpp/poco-default_json_impl/main.cpp @@ -0,0 +1,70 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class HelloRequestHandler : public Poco::Net::HTTPRequestHandler +{ +public: + virtual void handleRequest(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp) + { + resp.setStatus(Poco::Net::HTTPResponse::HTTP_OK); + + Poco::JSON::Array JSONArray; + + for (int i = 0; i < 10000; ++i) + { + Poco::JSON::Object::Ptr JSONObject = new Poco::JSON::Object(true); + + std::string id("item-"); id += std::to_string(i); + JSONObject->set("id", id); + JSONObject->set("name", "Hello World"); + JSONObject->set("type", "application"); + + JSONArray.add(Poco::Dynamic::Var(JSONObject)); + } + + std::ostream& out = resp.send(); + JSONArray.stringify(out); + out.flush(); + } +}; + +class HelloRequestHandlerFactory : public Poco::Net::HTTPRequestHandlerFactory +{ +public: + virtual Poco::Net::HTTPRequestHandler* createRequestHandler(const Poco::Net::HTTPServerRequest &) + { + return new HelloRequestHandler; + } +}; + +class HelloServerApp : public Poco::Util::ServerApplication +{ +protected: + int main(const std::vector &) + { + Poco::Net::ServerSocket socket(Poco::Net::SocketAddress(Poco::Net::AddressFamily::IPv4, 9000)); + Poco::Net::HTTPServer s(new HelloRequestHandlerFactory, socket, new Poco::Net::HTTPServerParams); + + s.start(); + waitForTerminationRequest(); + s.stop(); + + return Application::EXIT_OK; + } +}; + +int main(int argc, char** argv) +{ + HelloServerApp app; + return app.run(argc, argv); +} diff --git a/samples/cpp/poco-rapidjson/CMakeLists.txt b/samples/cpp/poco-rapidjson/CMakeLists.txt new file mode 100644 index 0000000..711c826 --- /dev/null +++ b/samples/cpp/poco-rapidjson/CMakeLists.txt @@ -0,0 +1,14 @@ +cmake_minimum_required(VERSION 3.5) +project(main) + +find_package(Poco REQUIRED COMPONENTS Foundation Net JSON Util) +find_package(RapidJSON REQUIRED) + +add_executable(main main.cpp) +target_include_directories(main PUBLIC ${RAPIDJSON_INCLUDE_DIRS}) +target_link_libraries(main + Poco::Foundation + Poco::Net + Poco::JSON + Poco::Util +) diff --git a/samples/cpp/poco-rapidjson/main.cpp b/samples/cpp/poco-rapidjson/main.cpp new file mode 100644 index 0000000..e40d06e --- /dev/null +++ b/samples/cpp/poco-rapidjson/main.cpp @@ -0,0 +1,76 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class HelloRequestHandler : public Poco::Net::HTTPRequestHandler +{ +public: + virtual void handleRequest(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp) + { + resp.setStatus(Poco::Net::HTTPResponse::HTTP_OK); + + char _id[20]; + + rapidjson::StringBuffer JSONBuffer; + rapidjson::Writer JSONWriter(JSONBuffer); + JSONWriter.StartArray(); + + for (int i = 0; i < 10000; ++i) + { + JSONWriter.StartObject(); + + snprintf(_id, sizeof(_id), "item-%d", i); + JSONWriter.Key("id"); JSONWriter.String(_id); + JSONWriter.Key("name"); JSONWriter.String("Hello World"); + JSONWriter.Key("type"); JSONWriter.String("application"); + + JSONWriter.EndObject(); + } + + JSONWriter.EndArray(); + + std::ostream& out = resp.send(); + out << JSONBuffer.GetString(); + out.flush(); + } +}; + +class HelloRequestHandlerFactory : public Poco::Net::HTTPRequestHandlerFactory +{ +public: + virtual Poco::Net::HTTPRequestHandler* createRequestHandler(const Poco::Net::HTTPServerRequest &) + { + return new HelloRequestHandler; + } +}; + +class HelloServerApp : public Poco::Util::ServerApplication +{ +protected: + int main(const std::vector &) + { + Poco::Net::ServerSocket socket(Poco::Net::SocketAddress(Poco::Net::AddressFamily::IPv4, 9000)); + Poco::Net::HTTPServer s(new HelloRequestHandlerFactory, socket, new Poco::Net::HTTPServerParams); + + s.start(); + waitForTerminationRequest(); + s.stop(); + + return Application::EXIT_OK; + } +}; + +int main(int argc, char** argv) +{ + HelloServerApp app; + return app.run(argc, argv); +}