Minimal server.
I used only:
/* * * Author, Copyright: Oleg Borodin <onborodin@gmail.com> * */ #include <iostream> #include <stdexcept> #include "server.hpp" int main(int argc, char **argv) { try { srv5::server server(1026, 2048, 10); server.team(); server.run(); } catch (std::exception& e) { std::cerr << "#exeption: " << e.what() << ", exit." << std::endl; return 1; } return 0; };
/* * * Author, Copyright: Oleg Borodin <onborodin@gmail.com> * */ #ifndef SERVER_HPP #define SERVER_HPP #include <sys/socket.h> #include <unistd.h> #include <thread> #include <mutex> #include <memory> namespace srv5 { class server { private: struct sockaddr_storage addr; int socket; int kqueue; int backlog; std::queue<int> queue; std::condition_variable cv; std::mutex mutex; std::vector<std::shared_ptr<std::thread>> pool; int threads; std::string timestamp(); void push(int socket); public: server(int port, int backlog, int threads); ~server(); void team(); void run(); }; } // namespace srv5 #endif
/* * * Author, Copyright: Oleg Borodin <onborodin@gmail.com> * */ #include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> #include <netinet/in.h> #include <unistd.h> #include <signal.h> #include <iostream> #include <fstream> #include <sstream> #include <functional> #include <condition_variable> #include <queue> #include <thread> #include <mutex> #include <chrono> #include <memory> #include <stdexcept> #include <iomanip> #include "server.hpp" namespace srv5 { server::server(int port, int backlog, int threads) : backlog(backlog), threads(threads) { if((socket = ::socket(PF_INET, SOCK_STREAM, 0)) < 0) { throw std::runtime_error("# cannot socket()"); } int optval = 1; if (::setsockopt(socket, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) < 0) { throw std::runtime_error("# cannot setsockopt()"); } auto paddr = reinterpret_cast<struct sockaddr_in*>(&addr); paddr->sin_family = AF_INET; paddr->sin_addr.s_addr = INADDR_ANY; paddr->sin_port = htons(port); paddr->sin_len = sizeof(struct sockaddr_in); if (::bind(socket, reinterpret_cast<struct sockaddr *>(paddr), paddr->sin_len) < 0) { throw std::runtime_error("# cannot bind()"); } } void server::run() { if (::listen(socket, backlog) < 0) { throw std::runtime_error("# cannot listen()"); } int newsocket; while ((newsocket = ::accept(socket, NULL, 0)) > 0) { push(std::move(newsocket)); } } void server::push(int socket) { std::unique_lock<std::mutex> lock(mutex); queue.push(socket); cv.notify_all(); } void server::team() { auto worker = [&]{ while(true) { std::unique_lock<std::mutex> lock(mutex); cv.wait(lock, [&]{ return !queue.empty(); }); while(!queue.empty()) { auto socket = queue.front(); queue.pop(); cv.notify_one(); char buffer[512]; ::read(socket, buffer, 512); std::stringstream body; for (int i = 0;i < 1000; i++) { body << "hello"; } std::stringstream head; head << "HTTP/1.1 200 OK\r\n"; head << "Date: " << timestamp() << "\r\n"; head << "Server: Srv3/0.1\r\n"; head << "Content-Length: " << body.str().length() << "\r\n"; head << "Content-Type: text/plain\r\n"; head << "Connection: close\r\n"; head << "\r\n"; std::string res; res.append(head.str()); res.append(body.str()); ::write(socket, res.c_str(), res.length()); ::shutdown(socket, SHUT_RDWR); ::close(socket); } } }; for (std::size_t i = 0; i < threads; ++i) { auto t = new std::thread(std::move(worker)); std::shared_ptr<std::thread> thread(std::move(t)); pool.push_back(thread); } for (std::size_t i = 0; i < pool.size(); ++i) { pool[i]->detach(); } } std::string server::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(); } server::~server() { ::close(kqueue); ::close(socket); } } // namespace srv5
With 2000 concurrent connection:
$ ab -c 2000 -n100000 '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 10000 requests
Completed 20000 requests
Completed 30000 requests
Completed 40000 requests
Completed 50000 requests
Completed 60000 requests
Completed 70000 requests
Completed 80000 requests
Completed 90000 requests
Completed 100000 requests
Finished 100000 requests
Server Software: Srv3/0.1
Server Hostname: localhost
Server Port: 1026
Document Path: /
Document Length: 10000 bytes
Concurrency Level: 2000
Time taken for tests: 14.059 seconds
Complete requests: 100000
Failed requests: 0
Total transferred: 1014200000 bytes
HTML transferred: 1000000000 bytes
Requests per second: 7112.90 [#/sec] (mean)
Time per request: 281.179 [ms] (mean)
Time per request: 0.141 [ms] (mean, across all concurrent requests)
Transfer rate: 70448.22 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 1 8.0 0 72
Processing: 46 277 57.9 265 697
Waiting: 1 277 57.9 265 697
Total: 116 278 59.6 265 721
Percentage of the requests served within a certain time (ms)
50% 265
66% 267
75% 267
80% 268
90% 288
95% 345
98% 533
99% 636
100% 721 (longest request)