HTTPサーバーを作ろうと思ったんです。それでBeastのExamplesを見てみたのですが、1番単純そうなServersのHTTP, synchronousをみても、ファイルサーバーを作るコードになっていて、まだまだ煩雑だと感じました。そこで、ファイルサーバーの処理を取り除いて、真にコアとなる処理を取り出して見ようと思いました。

常にHTTP 200 OKで空のレスポンスボディを返すようにしてみたところ、こんなコードになりました。ついでにHTTP Keep aliveへの対応やスレッドを作る処理も取っ払っています。

#include <boost/beast/core.hpp>
#include <boost/beast/http.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/config.hpp>
#include <cstdlib>
#include <iostream>
#include <memory>
#include <string>
 
namespace beast = boost::beast;
namespace http = beast::http;
namespace net = boost::asio;
using tcp = boost::asio::ip::tcp;
 
void fail(beast::error_code ec, char const* what)
{
    std::cerr << what << ": " << ec.message() << "\n";
}
 
void do_session(tcp::socket& socket)
{
    beast::error_code ec;
 
    beast::flat_buffer buffer;
    http::request<http::string_body> req;
    http::read(socket, buffer, req, ec);
    if(ec)
        return fail(ec, "read");
 
    http::response<http::empty_body> res{http::status::ok, 11};
    res.keep_alive(false);
    res.prepare_payload();
    http::serializer<false, http::empty_body> sr{res};
    http::write(socket, sr, ec);
    if(ec)
        return fail(ec, "write");
 
    socket.shutdown(tcp::socket::shutdown_send, ec);
}
 
int main(int argc, char* argv[])
{
    try
    {
        // Check command line arguments.
        if (argc != 3)
        {
            std::cerr <<
                "Usage: http-server-sync <address> <port> <doc_root>\n" <<
                "Example:\n" <<
                "    http-server-sync 0.0.0.0 8080 .\n";
            return EXIT_FAILURE;
        }
        auto const address = net::ip::make_address(argv[1]);
        auto const port = static_cast<unsigned short>(std::atoi(argv[2]));
 
        // The io_context is required for all I/O
        net::io_context ioc{1};
 
        // The acceptor receives incoming connections
        tcp::acceptor acceptor{ioc, {address, port}};
        for(;;)
        {
            // This will receive the new connection
            tcp::socket socket{ioc};
 
            // Block until we get a connection
            acceptor.accept(socket);
 
            // Launch the session
            do_session(socket);
        }
    }
    catch (const std::exception& e)
    {
        std::cerr << "Error: " << e.what() << std::endl;
        return EXIT_FAILURE;
    }
}

http::requestとhttp::responseクラスがあり、http::readとhttp::write関数があり、ボディーを表すクラスが何種類かあり、http::serializerクラスがあると言うことが分かりました。

まず、この辺りを必要に応じて作り替えていけばよいということが分かったので、満足しました。


スポンサード リンク

この記事のカテゴリ

  • ⇒ Boost.Beastの最小限のコードを作ってみることにした