There present minimal sample code. From tests the code limited ~2000 concurrent connection.
</code>
/* * * Author, Copyright: Oleg Borodin <onborodin@gmail.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #include <iostream> #include <string> #include <asio.hpp> #include "server.hpp" int main(int argc, char* argv[]) { try { server3::server server("0.0.0.0", "1026", 5); server.run(); } catch (std::exception& e) { std::cerr << "exception: " << e.what() << "\n"; } return 0; }
/* * * Author, Copyright: Oleg Borodin <onborodin@gmail.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #ifndef SERVER3_SERVER_HPP #define SERVER3_SERVER_HPP #include <string> #include <vector> #include <asio.hpp> #include "connection.hpp" namespace server3 { class server { private: std::size_t thread_pool_size; asio::io_context io_context; asio::signal_set signals; asio::ip::tcp::acceptor acceptor; std::shared_ptr<connection> new_connection; void accept(); void stop(); public: explicit server( const std::string& address, const std::string& port, std::size_t thread_pool_size ); void run(); server(const server&) = delete; server& operator=(const server&) = delete; }; } // namespace server3 #endif // HTTP_SERVER3_SERVER_HPP
/* * * Author, Copyright: Oleg Borodin <onborodin@gmail.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #include "server.hpp" #include <vector> #include <memory> namespace server3 { server::server(const std::string& address, const std::string& port, std::size_t thread_pool_size) : thread_pool_size(thread_pool_size), signals(io_context), acceptor(io_context), new_connection() { signals.add(SIGINT); signals.add(SIGTERM); auto signal_handler = [this](std::error_code ec, int signo) { stop(); }; signals.async_wait(signal_handler); asio::ip::tcp::resolver resolver(io_context); asio::ip::tcp::endpoint endpoint = *resolver.resolve(address, port).begin(); acceptor.open(endpoint.protocol()); acceptor.set_option(asio::ip::tcp::acceptor::reuse_address(true)); acceptor.bind(endpoint); acceptor.listen(2048); accept(); } void server::run() { std::vector<std::shared_ptr<asio::thread>> threads; for (std::size_t i = 0; i < thread_pool_size; ++i) { //std::shared_ptr<asio::thread> thread( //new asio::thread( //boost::bind(&asio::io_context::run, &io_context)) //); auto f = [this]{ io_context.run(); }; auto t = new asio::thread(std::move(f)); std::shared_ptr<asio::thread> thread(std::move(t)); threads.push_back(thread); } for (std::size_t i = 0; i < threads.size(); ++i) { threads[i]->join(); } } void server::accept() { new_connection.reset(new connection(io_context)); auto handler = [this](const asio::error_code& ec) { if (!ec) { new_connection->start(); } accept(); }; acceptor.async_accept(new_connection->get_socket(), handler); } void server::stop() { io_context.stop(); } } // namespace server3
/* * * Author, Copyright: Oleg Borodin <onborodin@gmail.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #ifndef SERVER3_CONNECTION_HPP #define SERVER3_CONNECTION_HPP #include <memory> #include <array> #include <asio.hpp> namespace server3 { class connection : public std::enable_shared_from_this<connection> { private: asio::io_context::strand strand; asio::ip::tcp::socket socket; std::string response; std::string buffer; void read(); void write(); public: explicit connection(asio::io_context& io_context); connection(const connection&) = delete; connection& operator=(const connection&) = delete; asio::ip::tcp::socket& get_socket(); void start(); }; } // namespace server3 #endif // HTTP_SERVER3_CONNECTION_HPP
/* * * Author, Copyright: Oleg Borodin <onborodin@gmail.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #include <vector> #include <sstream> #include <filesystem> #include <utility> #include <iomanip> #include <chrono> #include "connection.hpp" namespace server3 { connection::connection(asio::io_context& io_context) : strand(io_context), socket(io_context) {} asio::ip::tcp::socket& connection::get_socket() { return socket; } void connection::start() { do_read(); } void connection::read() { auto self(shared_from_this()); auto handler = [this, self](std::error_code ec, std::size_t bytes_transferred) { if (!ec) { write(); } else if (ec != asio::error::operation_aborted) { socket.close(); } }; std::string delimeter = "\r\n\r\n"; asio::async_read_until(socket, asio::dynamic_buffer(buffer), delimeter, handler); } std::string timestamp() { std::stringstream ss; std::time_t now = std::time(0); ss << std::put_time(std::gmtime(&now), "%a, %d %b %Y %T %Z"); return ss.str(); } void connection::write() { std::stringstream content; for (int i = 0; i < 100000; i++) { content << "hello!\n"; } std::stringstream header; header << "HTTP/1.1 200 OK\r\n"; header << "Date: " << timestamp() << "\r\n"; header << "Server: Srv3/0.1\r\n"; header << "Content-Length: " << content.str().length() << "\r\n"; header << "Content-Type: text/plain\r\n"; header << "Connection: close\r\n"; header << "\r\n"; response += header.str(); response += content.str(); auto self(shared_from_this()); auto handler = [this, self](std::error_code ec, std::size_t) { if (!ec) { asio::error_code ignored_ec; socket.shutdown(asio::ip::tcp::socket::shutdown_both, ignored_ec); } if (ec != asio::error::operation_aborted) { socket.close(); } }; asio::async_write(socket, asio::buffer(response), asio::bind_executor(strand, handler)); } } // namespace server3
$ gmake gmake all-am gmake[1]: Entering directory '/home/user/srv7std' clang++ -std=c++17 -DHAVE_CONFIG_H -I. -pthread -I/usr/local/include -Wall -g -O2 -MT main.o -MD -MP -MF .deps/main.Tpo -c -o main.o main.cpp mv -f .deps/main.Tpo .deps/main.Po clang++ -std=c++17 -DHAVE_CONFIG_H -I. -pthread -I/usr/local/include -Wall -g -O2 -MT connection.o -MD -MP -MF .deps/connection.Tpo -c -o connection.o connection.cpp mv -f .deps/connection.Tpo .deps/connection.Po clang++ -std=c++17 -DHAVE_CONFIG_H -I. -pthread -I/usr/local/include -Wall -g -O2 -MT server.o -MD -MP -MF .deps/server.Tpo -c -o server.o server.cpp mv -f .deps/server.Tpo .deps/server.Po clang++ -std=c++17 -pthread -I/usr/local/include -Wall -g -O2 -o srv7 main.o connection.o server.o -L/usr/local/lib -pthread gmake[1]: Leaving directory '/home/user/srv7std'
$ ab -c 2000 -n10000 'http://localhost:1026/'
This is ApacheBench, Version 2.3 <$Revision: 1826891 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking localhost (be patient)
Completed 1000 requests
Completed 2000 requests
Completed 3000 requests
Completed 4000 requests
Completed 5000 requests
Completed 6000 requests
Completed 7000 requests
Completed 8000 requests
Completed 9000 requests
Completed 10000 requests
Finished 10000 requests
Server Software: Srv3/0.1
Server Hostname: localhost
Server Port: 1026
Document Path: /
Document Length: 700000 bytes
Concurrency Level: 2000
Time taken for tests: 39.064 seconds
Complete requests: 10000
Failed requests: 0
Total transferred: 7001430000 bytes
HTML transferred: 7000000000 bytes
Requests per second: 255.99 [#/sec] (mean)
Time per request: 7812.703 [ms] (mean)
Time per request: 3.906 [ms] (mean, across all concurrent requests)
Transfer rate: 175031.21 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 12 107.1 0 1115
Processing: 526 6834 2158.2 8024 8883
Waiting: 23 6613 2169.9 7809 8499
Total: 1591 6846 2129.8 8025 8884
Percentage of the requests served within a certain time (ms)
50% 8025
66% 8454
75% 8508
80% 8531
90% 8586
95% 8640
98% 8694
99% 8730
100% 8884 (longest request)