如何设置接受器在unix域和tcp套接字上接受?

问题描述 投票:0回答:1

我正在编写一个服务器类,我希望能够支持任何流协议。

此页面提供了一些提示:https://beta.boost.org/doc/libs/1_83_0/doc/html/boost_asio/overview/networking/other_protocols.html

然而,受体部分却相当难以捉摸……

您是否有关于如何设置

acceptor
以与
boost::asio::generic::stream_protocol::endpoint
一起使用的示例(至少可以是 ip/TCP 或 unix 域)?

c++ unix tcp boost-asio
1个回答
0
投票

您需要有多个侦听器,例如

template <typename Socket> struct Listener {
    using Proto    = typename Socket::protocol_type;
    using Acceptor = asio::basic_socket_acceptor<Proto>;
    using Endpoint = Acceptor::endpoint_type;

    Listener(asio::any_io_executor ex, Endpoint ep) : acc_(std::move(ex), std::move(ep)) { accept_loop(); }

  private:
    void accept_loop() {
        acc_.async_accept([](error_code ec, Socket s) {
            std::cout << "Accepted (" << ec.message() << ") from " << s.remote_endpoint() << std::endl;
            if (!ec)
                std::make_shared<Session<Socket>>(std::move(s))->Start();
        });
    }
    Acceptor acc_;
};

正如您所看到的,会话类也是在套接字类型上模板化的,因此您只需要实现一次:

template <typename Socket> struct Session /*: BaseSession*/ {
    Session(Socket s) : sock_(std::move(s)) {}

    void Start() {
        read_loop();
    }

  private:
    void read_loop() {
        async_read_until(sock_, asio::dynamic_buffer(message), "\n",
                         [this, self = shared_from_this()](error_code ec, size_t n) {
                             std::cout << "Received (" << ec.message() << "): "              //
                                       << quoted(std::string_view(message).substr(0, n - 1)) //
                                       << std::endl;

                            if (!ec) {
                                message.erase(0, n);
                                read_loop();
                            }
                         });
    }
    std::string message;
    Socket sock_;
};

如果您需要对所有会话实例进行通用操作,请考虑基类。

现在多服务器就这么简单:

struct MultiServer {
    MultiServer(asio::any_io_executor ex, std::set<uint16_t> tcp_listen_ports, std::set<std::string> unix_domain_socket) {
        for (auto p : tcp_listen_ports)
            listeners_.push_back(std::make_shared<Listener<tcp::socket>>(ex, tcp::endpoint{{}, p}));
        for (auto& s : unix_domain_socket)
            listeners_.push_back(std::make_shared<Listener<uxd::socket>>(ex, s));
    }

  private:
    std::vector<std::shared_ptr<void> > listeners_;
};

int main() {
    asio::io_context ioc;
    MultiServer      multi(ioc.get_executor(), {8989, 7979}, {"socket1", "socket2"});

    ioc.run_for(10s); // limited for Coliru
}

这将运行一个服务器,侦听 2 个 tcp 端口和 2 个 unix 域套接字,并在所有端口上生成相同的会话:

完整列表

住在Coliru

#include <boost/asio.hpp>
#include <iomanip>
#include <iostream>
#include <set>
namespace asio = boost::asio;
using namespace std::chrono_literals;
using boost::system::error_code;
using tcp = asio::ip::tcp;
using uxd = asio::local::stream_protocol;

struct BaseSession : std::enable_shared_from_this<BaseSession> {
    // in case you need any "common" behavior
    // virtual ~BaseSession() = default;
};

template <typename Socket> struct Session : BaseSession {
    Session(Socket s) : sock_(std::move(s)) {}

    void Start() {
        read_loop();
    }

  private:
    void read_loop() {
        async_read_until(sock_, asio::dynamic_buffer(message), "\n",
                         [this, self = shared_from_this()](error_code ec, size_t n) {
                             std::cout << "Received (" << ec.message() << "): "              //
                                       << quoted(std::string_view(message).substr(0, n - 1)) //
                                       << std::endl;

                            if (!ec) {
                                message.erase(0, n);
                                read_loop();
                            }
                         });
    }
    std::string message;
    Socket sock_;
};

template <typename Socket> struct Listener {
    using Proto    = typename Socket::protocol_type;
    using Acceptor = asio::basic_socket_acceptor<Proto>;
    using Endpoint = Acceptor::endpoint_type;

    Listener(asio::any_io_executor ex, Endpoint ep) : acc_(std::move(ex), std::move(ep)) { accept_loop(); }

  private:
    void accept_loop() {
        acc_.async_accept([](error_code ec, Socket s) {
            std::cout << "Accepted (" << ec.message() << ") from " << s.remote_endpoint() << std::endl;
            if (!ec)
                std::make_shared<Session<Socket>>(std::move(s))->Start();
        });
    }
    Acceptor acc_;
};

struct MultiServer {
    MultiServer(asio::any_io_executor ex, std::set<uint16_t> tcp_listen_ports, std::set<std::string> unix_domain_socket) {
        for (auto p : tcp_listen_ports)
            listeners_.push_back(std::make_shared<Listener<tcp::socket>>(ex, tcp::endpoint{{}, p}));
        for (auto& s : unix_domain_socket)
            listeners_.push_back(std::make_shared<Listener<uxd::socket>>(ex, s));
    }

  private:
    std::vector<std::shared_ptr<void> > listeners_;
};

int main() {
    asio::io_context ioc;
    MultiServer      multi(ioc.get_executor(), {8989, 7979}, {"socket1", "socket2"});

    ioc.run_for(10s); // limited for Coliru
}
© www.soinside.com 2019 - 2024. All rights reserved.