• 2403C++,C++20协程库


    原文

    基于C++20协程http--cinatra

    cinatra是基于C++20无栈协程实现的跨平台,仅头,高性能,易用的http/https(http1.1),包括httpserverhttpclient,功能完备,不仅支持最普通的getpost等请求,还支持restfulapi,websocket,chunked,ranges,multipart,静态文件服务和反向代理等功能.

    后面会分别介绍这些功能,文末也专门附上benchmark测试代码.

    2.基本http请求

    2.1.启动http服务器

    #include 
    using namespace cinatra;
    void start_server() {
      coro_http_server server(/*`thread_num=`*/std::thread::hardware_concurrency(), 9001);
      server.set_http_handler<GET>(
          "/", [](coro_http_request &req, coro_http_response &resp) {
            resp.set_status_and_content(status_type::ok, "ok"); //`IO`线程中的响应
          });
      server.set_http_handler<GET, POST>(
          "/in_thread_pool",
          [](coro_http_request &req,
             coro_http_response &resp) -> async_simple::coro::Lazy<void> {
            //在线程池中休息.
            co_await coro_io::post([&] {
              resp.set_status_and_content(status_type::ok, "ok in thread pool");
            });
          });
       server.sync_start();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    几行代码即可创建一个http服务,先设置httpserver工作线程数和端口.然后设置http服务的url,httpmethod和对应的处理函数.
    可在io线程或线程池中处理http请求.

    2.2.client发请求

    #include 
    using namespace cinatra;
    async_simple::coro::Lazy<void> do_request() {
      coro_http_client client{};
      auto result = co_await client.async_get("http://127.0.0.1:9001/");
      assert(result.status == 200);
      assert(result.resp_body == "ok");
      for (auto [key, val] : result.resp_headers) {
        std::cout << key << ": " << val << "\n";
      }
      result = co_await client.async_get("/in_thread_pool");
      assert(result.status == 200);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    httpclient异步请求服务器,返回结果中包括服务端响应的状态码,httpcontenthttp头,如果网络错误,可从result.net_err中取错码和错误message.

    2.3.restfulapi

      coro_http_server server(/*`thread_num=`*/std::thread::hardware_concurrency(), 9001);
      server.set_http_handler<cinatra::GET, cinatra::POST>(
          "/test2/{}/test3/{}",
          [](coro_http_request &req,
             coro_http_response &resp) -> async_simple::coro::Lazy<void> {
            co_await coro_io::post([&]() {
              CHECK(req.matches_.str(1) == "name");
              CHECK(req.matches_.str(2) == "test");
              resp.set_status_and_content(cinatra::status_type::ok, "hello world");
            });
            co_return;
          });
      server.set_http_handler<cinatra::GET, cinatra::POST>(
          R"(/numbers/(\d+)/test/(\d+))",
          [](coro_http_request &req, coro_http_response &response) {
            CHECK(req.matches_.str(1) == "100");
            CHECK(req.matches_.str(2) == "200");
            response.set_status_and_content(status_type::ok, "number regex ok");
          });
      server.set_http_handler<cinatra::GET, cinatra::POST>(
          "/user/:id", [](coro_http_request &req, coro_http_response &response) {
            CHECK(req.params_["id"] == "cinatra");
            response.set_status_and_content(status_type::ok, "ok");
          });
      server.set_http_handler<cinatra::GET, cinatra::POST>(
          "/user/:id/subscriptions",
          [](coro_http_request &req, coro_http_response &response) {
            CHECK(req.params_["id"] == "subid");
            response.set_status_and_content(status_type::ok, "ok");
          });
      server.set_http_handler<cinatra::GET, cinatra::POST>(
          "/values/:x/:y/:z",
          [](coro_http_request &req, coro_http_response &response) {
            CHECK(req.params_["x"] == "guilliman");
            CHECK(req.params_["y"] == "cawl");
            CHECK(req.params_["z"] == "yvraine");
            response.set_status_and_content(status_type::ok, "ok");
          });
      server.async_start();
      coro_http_client client;
      client.get("http://127.0.0.1:9001/test2/name/test3/test");
      client.get("http://127.0.0.1:9001/numbers/100/test/200");
      client.get("http://127.0.0.1:9001/user/cinatra");
      client.get("http://127.0.0.1:9001/user/subid/subscriptions");
      client.get("http://127.0.0.1:9001/value/guilliman/cawl/yvraine");
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46

    2.4. https访问

    #ifdef CINATRA_ENABLE_SSL
      coro_http_client client{};
      result = co_await client.async_get("https://www.taobao.com");
      assert(result.status == 200);
    #endif
    
    • 1
    • 2
    • 3
    • 4
    • 5

    访问https网站时,确保已安装了openssl并开启了ENABLE_SSL.

    3. websocket

      cinatra::coro_http_server server(1, 9001);
      server.set_http_handler<cinatra::GET>(
          "/ws_echo",
          [](cinatra::coro_http_request &req,
             cinatra::coro_http_response &resp) -> async_simple::coro::Lazy<void> {
            cinatra::websocket_result result{};
            while (true) {
              result = co_await req.get_conn()->read_websocket();
              if (result.ec) {
                break;
              }
              if (result.type == cinatra::ws_frame_type::WS_CLOSE_FRAME) {
                REQUIRE(result.data == "test close");
                break;
              }
              auto ec = co_await req.get_conn()->write_websocket(result.data);
              if (ec) {
                break;
              }
            }
          });
      server.sync_start();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    在协程处理函数中,while循环异步读写websocket数据.

    client端:

      cinatra::coro_http_client client{};
      std::string message(100, 'x');
      client.on_ws_close([](std::string_view reason) {
          std::cout << "web socket close " << reason << std::endl;
      });
      client.on_ws_msg([message](cinatra::resp_data data) {
        if (data.net_err) {
          std::cout << "ws_msg net error " << data.net_err.message() << "\n";
          return;
        }
        std::cout << "ws msg len: " << data.resp_body.size() << std::endl;
        REQUIRE(data.resp_body == message);
      });
      co_await client.async_ws_connect("ws://127.0.0.1:9001/ws_echo");
      co_await client.async_send_ws(message);
      co_await client.async_send_ws_close("test close");
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    client设置读回调和close回调分别处理收到的websocket消息和websocketclose消息.

    4.静态文件服务

      std::string filename = "temp.txt";
      create_file(filename, 64);
      coro_http_server server(1, 9001);
      std::string virtual_path = "download";
      std::string files_root_path = "";  //当前路径
      server.set_static_res_dir(
          virtual_path,
          files_root_path);//在服务器启动之前设置此项,如果添加新文件,则需要重启服务器.
      server.async_start();
      coro_http_client client{};
      auto result =
          co_await client.async_get("http://127.0.0.1:9001/download/temp.txt");
      assert(result.status == 200);
      assert(result.resp_body.size() == 64);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    服务端设置虚路径和实际文件路径,下载文件时输入虚路径实际路径下的文件名即可实现下载.

    5.反向代理

    假设有3个服务器需要代理,代理服务器根据负载均衡算法来选择其中的一个来访问并把结果返回给客户.

    5.1.先启动3个被代理的服务器

      cinatra::coro_http_server web_one(1, 9001);
      web_one.set_http_handler<cinatra::GET, cinatra::POST>(
          "/",
          [](coro_http_request &req,
             coro_http_response &response) -> async_simple::coro::Lazy<void> {
            co_await coro_io::post([&]() {
              response.set_status_and_content(status_type::ok, "web1");
            });
          });
      web_one.async_start();
      cinatra::coro_http_server web_two(1, 9002);
      web_two.set_http_handler<cinatra::GET, cinatra::POST>(
          "/",
          [](coro_http_request &req,
             coro_http_response &response) -> async_simple::coro::Lazy<void> {
            co_await coro_io::post([&]() {
              response.set_status_and_content(status_type::ok, "web2");
            });
          });
      web_two.async_start();
      cinatra::coro_http_server web_three(1, 9003);
      web_three.set_http_handler<cinatra::GET, cinatra::POST>(
          "/", [](coro_http_request &req, coro_http_response &response) {
            response.set_status_and_content(status_type::ok, "web3");
          });
      web_three.async_start();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    5.2.启动代理服务器

    设置roundrobin策略的代理服务器:

      coro_http_server proxy_rr(2, 8091);
      proxy_rr.set_http_proxy_handler<GET, POST>(
          "/rr", {"127.0.0.1:9001", "127.0.0.1:9002", "127.0.0.1:9003"},
          coro_io::load_blance_algorithm::RR);
      proxy_rr.sync_start();
    
    • 1
    • 2
    • 3
    • 4
    • 5

    设置random策略的代理服务器:

      coro_http_server proxy_random(2, 8092);
      proxy_random.set_http_proxy_handler<GET, POST>(
          "/random", {"127.0.0.1:9001", "127.0.0.1:9002", "127.0.0.1:9003"});
      proxy_random.sync_start();
    
    • 1
    • 2
    • 3
    • 4

    设置weightroundrobin策略的代理服务器:

      coro_http_server proxy_wrr(2, 8090);
      proxy_wrr.set_http_proxy_handler<GET, POST>(
          "/wrr", {"127.0.0.1:9001", "127.0.0.1:9002", "127.0.0.1:9003"},
          coro_io::load_blance_algorithm::WRR, {10, 5, 5});
      proxy_wrr.sync_start();  
    
    • 1
    • 2
    • 3
    • 4
    • 5

    5.3.client请求代理服务器

      coro_http_client client_rr;
      resp_data resp_rr = client_rr.get("http://127.0.0.1:8091/rr");
      assert(resp_rr.resp_body == "web1");
      resp_rr = client_rr.get("http://127.0.0.1:8091/rr");
      assert(resp_rr.resp_body == "web2");
      resp_rr = client_rr.get("http://127.0.0.1:8091/rr");
      assert(resp_rr.resp_body == "web3");
      coro_http_client client_wrr;
      resp_data resp = client_wrr.get("http://127.0.0.1:8090/wrr");
      assert(resp.resp_body == "web1");
      resp = client_wrr.get("http://127.0.0.1:8090/wrr");
      assert(resp.resp_body == "web1");
      resp = client_wrr.get("http://127.0.0.1:8090/wrr");
      assert(resp.resp_body == "web2");
      resp = client_wrr.get("http://127.0.0.1:8090/wrr");
      assert(resp.resp_body == "web3");  
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    6.增加切面

    6.1.创建任意切面

    struct log_t {
      bool before(coro_http_request &, coro_http_response &) {
        std::cout << "before log" << std::endl;
        return true;
      }
      bool after(coro_http_request &, coro_http_response &res) {
        std::cout << "after log" << std::endl;
        res.add_header("aaaa", "bbcc");
        return true;
      }
    };
    struct get_data {
      bool before(coro_http_request &req, coro_http_response &res) {
        req.set_aspect_data("hello world");
        return true;
      }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    切面是实现了beforeafter函数的类.

    6.2.应用切面

    async_simple::coro::Lazy<void> use_aspects() {
      coro_http_server server(1, 9001);
      server.set_http_handler<GET>(
          "/get",
          [](coro_http_request &req, coro_http_response &resp) {
            auto val = req.get_aspect_data();
            assert(val[0] == "hello world");
            resp.set_status_and_content(status_type::ok, "ok");
          },
          log_t{}, get_data{});//设置了两个切面,可按需设置任意个切面
      server.async_start();
      coro_http_client client{};
      auto result = co_await client.async_get("http://127.0.0.1:9001/get");
      assert(result.status == 200);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    注册httphandler时设置了两个切面,该url的处理会先进入切面,切面返回true,才会继续往下执行业务逻辑,如果返回false则不会执行后续逻辑,返回false时,要在切面中调用resp.set_status_and_content设置状态码返回内容.

    7.chunked,ranges,multipart

    7.1.chunked上传下载

    chunked协议适合大文件上传和下载:

    async_simple::coro::Lazy<void> chunked_upload_download() {
      coro_http_server server(1, 9001);
      server.set_http_handler<GET, POST>(
          "/chunked",
          [](coro_http_request &req,
             coro_http_response &resp) -> async_simple::coro::Lazy<void> {
            assert(req.get_content_type() == content_type::chunked);
            chunked_result result{};
            std::string content;
            while (true) {
              result = co_await req.get_conn()->read_chunked();
              if (result.ec) {
                co_return;
              }
              if (result.eof) {
                break;
              }
              content.append(result.data);
            }
            std::cout << "content size: " << content.size() << "\n";
            std::cout << content << "\n";
            resp.set_format_type(format_type::chunked);
            resp.set_status_and_content(status_type::ok, "chunked ok");
          });
      server.set_http_handler<GET, POST>(
          "/write_chunked",
          [](coro_http_request &req,
             coro_http_response &resp) -> async_simple::coro::Lazy<void> {
            resp.set_format_type(format_type::chunked);
            bool ok;
            if (ok = co_await resp.get_conn()->begin_chunked(); !ok) {
              co_return;
            }
            std::vector<std::string> vec{"hello", " world", " ok"};
            for (auto &str : vec) {
              if (ok = co_await resp.get_conn()->write_chunked(str); !ok) {
                co_return;
              }
            }
            ok = co_await resp.get_conn()->end_chunked();
          });
      server.sync_start();
      result = co_await client.async_get("http://127.0.0.1:9001/write_chunked");
      assert(result.status == 200);
      assert(result.resp_body == "hello world ok");
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46

    clientchunked上传文件

    coro_http_client client{};
      std::string filename = "test.txt";
      create_file(filename, 1010);
      coro_io::coro_file file{};
      co_await file.async_open(filename, coro_io::flags::read_only);
      std::string buf;
      detail::resize(buf, 100);
      auto fn = [&file, &buf]() -> async_simple::coro::Lazy<read_result> {
        auto [ec, size] = co_await file.async_read(buf.data(), buf.size());
        co_return read_result{buf, file.eof(), ec};
      };
      auto result = co_await client.async_upload_chunked(
          "http://127.0.0.1:9001/chunked"sv, http_method::POST, std::move(fn));
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    client读文件分块上传文件整个过程都是异步的.

    clientchunked下载文件:

      auto result = co_await client.async_get("http://127.0.0.1:9001/write_chunked");
      assert(result.status == 200);
      assert(result.resp_body == "hello world ok");
    
    • 1
    • 2
    • 3

    这样下载内存中,也可下载文件中.

      auto result = co_await client.async_download(
            "http://127.0.0.1:9001/write_chunked", "download.txt");
      CHECK(std::filesystem::file_size("download.txt")==1010);
    
    • 1
    • 2
    • 3

    7.2.ranges下载

    async_simple::coro::Lazy<void> byte_ranges_download() {
      create_file("test_multiple_range.txt", 64);
      coro_http_server server(1, 8090);
      server.set_static_res_dir("", "");
      server.async_start();
      std::this_thread::sleep_for(200ms);
      std::string uri = "http://127.0.0.1:8090/test_multiple_range.txt";
      {
        std::string filename = "test1.txt";
        std::error_code ec{};
        std::filesystem::remove(filename, ec);
        coro_http_client client{};
        resp_data result = co_await client.async_download(uri, filename, "1-10");
        assert(result.status == 206);
        assert(std::filesystem::file_size(filename) == 10);
        filename = "test2.txt";
        std::filesystem::remove(filename, ec);
        result = co_await client.async_download(uri, filename, "10-15");
        assert(result.status == 206);
        assert(std::filesystem::file_size(filename) == 6);
      }
      {
        coro_http_client client{};
        std::string uri = "http://127.0.0.1:8090/test_multiple_range.txt";
        client.add_header("Range", "bytes=1-10,20-30");
        auto result = co_await client.async_get(uri);
        assert(result.status == 206);
        assert(result.resp_body.size() == 21);
        std::string filename = "test_ranges.txt";
        client.add_header("Range", "bytes=0-10,21-30");
        result = co_await client.async_download(uri, filename);
        assert(result.status == 206);
        assert(fs::file_size(filename) == 21);
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    7.3.multipart上传下载

      coro_http_server server(1, 8090);
      server.set_http_handler<cinatra::PUT, cinatra::POST>(
          "/multipart_upload",
          [](coro_http_request &req,
             coro_http_response &resp) -> async_simple::coro::Lazy<void> {
            assert(req.get_content_type() == content_type::multipart);
            auto boundary = req.get_boundary();
            multipart_reader_t multipart(req.get_conn());
            while (true) {
              auto part_head = co_await multipart.read_part_head();
              if (part_head.ec) {
                co_return;
              }
              std::cout << part_head.name << "\n";
              std::cout << part_head.filename << "\n";
              std::shared_ptr<coro_io::coro_file> file;
              std::string filename;
              if (!part_head.filename.empty()) {
                file = std::make_shared<coro_io::coro_file>();
                filename = std::to_string(
                    std::chrono::system_clock::now().time_since_epoch().count());
                size_t pos = part_head.filename.rfind('.');
                if (pos != std::string::npos) {
                  auto extent = part_head.filename.substr(pos);
                  filename += extent;
                }
                std::cout << filename << "\n";
                co_await file->async_open(filename, coro_io::flags::create_write);
                if (!file->is_open()) {
                  resp.set_status_and_content(status_type::internal_server_error, "file open failed");
                  co_return;
                }
              }
              auto part_body = co_await multipart.read_part_body(boundary);
              if (part_body.ec) {
                co_return;
              }
              if (!filename.empty()) {
                auto ec = co_await file->async_write(part_body.data.data(), part_body.data.size());
                if (ec) {
                  co_return;
                }
                file->close();
                CHECK(fs::file_size(filename) == 1024);
              }
              else {
                std::cout << part_body.data << "\n";
              }
              if (part_body.eof) {
                break;
              }
            }
            resp.set_status_and_content(status_type::ok, "ok");
            co_return;
          });
      server.async_start();
      std::string filename = "test_1024.txt";
      create_file(filename);
      coro_http_client client{};
      std::string uri = "http://127.0.0.1:8090/multipart_upload";
      client.add_str_part("test", "test value");
      client.add_file_part("test file", filename);
      auto result =
          async_simple::coro::syncAwait(client.async_upload_multipart(uri));
      CHECK(result.status == 200);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65

    8.benchmarkcode

    8.1. brpc http benchmark code
    DEFINE_int32(port, 9001, "TCP Port of this server");
    DEFINE_int32(idle_timeout_s, -1,
                 "Connection will be closed if there is no "
                 "read/write operations during the last `idle_timeout_s'");
    class HttpServiceImpl : public HttpService {
    public:
      HttpServiceImpl() {}
      virtual ~HttpServiceImpl() {}
      void Echo(google::protobuf::RpcController *cntl_base, const HttpRequest *,
                HttpResponse *, google::protobuf::Closure *done) {
        brpc::ClosureGuard done_guard(done);
        brpc::Controller *cntl = static_cast<brpc::Controller *>(cntl_base);
        std::string date_str{get_gmt_time_str()};
        cntl->http_response().SetHeader("Date", date_str);
        cntl->http_response().SetHeader("Server", "brpc");
        cntl->http_response().set_content_type("text/plain");
        butil::IOBufBuilder os;
        os << "hello, world!";
        os.move_to(cntl->response_attachment());
      }
    };
    int main(int argc, char *argv[]) {
      GFLAGS_NS::ParseCommandLineFlags(&argc, &argv, true);
      brpc::Server server;
      example::HttpServiceImpl http_svc;
      if (server.AddService(&http_svc, brpc::SERVER_DOESNT_OWN_SERVICE) != 0) {
        LOG(ERROR) << "Fail to add http_svc";
        return -1;
      }
      brpc::ServerOptions options;
      options.idle_timeout_sec = FLAGS_idle_timeout_s;
      if (server.Start(FLAGS_port, &options) != 0) {
        LOG(ERROR) << "Fail to start HttpServer";
        return -1;
      }
      server.RunUntilAskedToQuit();
      return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    8.2.drogonbenchmarkcode

    #include 
    using namespace drogon;
    int main() {
        app()
        .setLogPath("./")
        .setLogLevel(trantor::Logger::kWarn)
        .addListener("0.0.0.0", 9001)
        .setThreadNum(0)
        .registerSyncAdvice([](const HttpRequestPtr &req) -> HttpResponsePtr {
            auto response = HttpResponse::newHttpResponse();
            response->setBody("Hello, world!");
            return response;
        })
        .run();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    8.3.nginxhttp配置

    user nginx;
    worker_processes auto;
    worker_cpu_affinity auto;
    error_log stderr error;
    #worker_rlimit_nofile 1024000;
    timer_resolution 1s;
    daemon off;
    events {
        worker_connections 32768;
        multi_accept off; #default
    }
    http {
        include /etc/nginx/mime.types;
        access_log off;
        server_tokens off;
        msie_padding off;
        sendfile off; #default
        tcp_nopush off; #default
        tcp_nodelay on; #default
        keepalive_timeout 65;
        keepalive_disable none; #default msie6
        keepalive_requests 300000; #default 100
        server {
            listen 9001 default_server reuseport deferred fastopen=4096;
            root /;
            location = /plaintext {
                default_type text/plain;
                return 200 "Hello, World!";
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    8.4.cinatrabenchmarkcode

    #include 
    using namespace cinatra;
    using namespace std::chrono_literals;
    int main() {
      coro_http_server server(std::thread::hardware_concurrency(), 8090);
      server.set_http_handler<GET>(
          "/plaintext", [](coro_http_request& req, coro_http_response& resp) {
            resp.get_conn()->set_multi_buf(false);
            resp.set_content_type<resp_content_type::txt>();
            resp.set_status_and_content(status_type::ok, "Hello, world!");
          });
      server.sync_start();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
  • 相关阅读:
    数据指标体系建设思考(二)
    vue导航栏下拉菜单(附带展开收缩动画)
    【EI会议2023】12.20之后ddl
    无穷级数几个基础知识
    中兴设备show命令大全
    PyQt5可视化编程-控件
    django-rest-framework 基础三 认证、权限和频率
    mariadb安装密码验证插件
    前端——HTML基础
    deepxde更改backend
  • 原文地址:https://blog.csdn.net/fqbqrr/article/details/136404873