最近Boost.Asioのリファレンスを見ていて、async_acceptのオーバーロードが増えていることに気付きました: basic_socket_acceptor::async_accept – 1.66.0

このページを見る限り、仮引数でbasic_socket<>を受け取らないものが加わっていたのです。もしかして、と思い確認するとやはりそうでした。内部でsocketを作ってacceptするらしく、コールバック関数などでaccept済みのソケットを受け取るというものになっています。

#include <cstdlib>
#include <cstring>
#include <iostream>
#include <memory>
#include <boost/asio.hpp>
 
using tcp = boost::asio::ip::tcp;
 
class Connection : public std::enable_shared_from_this<Connection>
{
public:
    static std::shared_ptr<Connection> Run(tcp::socket&& s)
    {
        auto p = std::make_shared<Connection>(std::move(s));
        p->RunImpl();
        return p;
    }
 
    Connection(tcp::socket&& s)
        : m_socket(std::move(s))
    {
    }
 
    ~Connection() = default;
 
private:
    void RunImpl()
    {
        boost::asio::async_write(m_socket, boost::asio::buffer(MESSAGE, std::strlen(MESSAGE)),
            [self = shared_from_this()](boost::system::error_code ec, std::size_t)
        {
            if (ec)
            {
                std::cerr << "write error: " << ec << std::endl;
            }
        });
    }
 
    tcp::socket m_socket;
 
    static inline constexpr const char MESSAGE[] = "OK";
 
    Connection(Connection&&) = delete;
    Connection(const Connection&) = delete;
    Connection& operator=(Connection&&) = delete;
    Connection& operator=(const Connection&) = delete;
};
 
class TcpServer
{
public:
    TcpServer(boost::asio::io_context& context, tcp::endpoint endpoint)
        : m_acceptor(context, endpoint)
    {
    }
 
    void Run()
    {
        m_acceptor.async_accept([this](boost::system::error_code ec, tcp::socket s)
        {
            OnAccept(ec, std::move(s));
        });
    }
 
    ~TcpServer() = default;
 
private:
    void OnAccept(boost::system::error_code ec, tcp::socket s)
    {
        if (ec)
        {
            std::cerr << "accept error: " << ec << std::endl;
        }
        else
        {
            Connection::Run(std::move(s));
        }
        Run();
    }
 
    tcp::acceptor m_acceptor;
 
    TcpServer(TcpServer&&) = delete;
    TcpServer(const TcpServer&) = delete;
    TcpServer& operator=(TcpServer&&) = delete;
    TcpServer& operator=(const TcpServer&) = delete;
};
 
int main()
{
    boost::asio::io_context context;
    TcpServer server(context, tcp::endpoint(tcp::v4(), 5000));
    server.Run();
    context.run();
    std::quick_exit(0);
}

どうやら1.66.0から追加されたようです。Boost 1.66.0リリースノート – boostjpより:

basic_socket_acceptor::async_accept()がソケットの参照をパラメータでとっていたが、ハンドラに渡されるよう変更。これはC++11以降でムーブサポートされている場合のみ使用できる

Boost.Asio公式のexampleも1.65と1.66とで変更が入っていました。見比べるとserverクラスのメンバー変数socket_が不要になったことが分かります。

地味ながら便利な変更点だと思います。


スポンサード リンク

この記事のカテゴリ

  • ⇒ async_acceptにソケットを渡す必要がなくなっていた