可重载的 boost::asio::basic_stream_socket

发布于 2025-01-08 17:03:53 字数 472 浏览 1 评论 0原文

开发网络应用程序时,我有一个 Connection 类来管理在网络上发送和接收消息。我正在使用 boost::asio。

我现在想让 Connection 类处理通过 TCP 和本地 UNIX 流套接字的连接。然而,boost 的模板设计让我感到困惑。 AFAICT,local::stream_protocol::socket 和 ip::tcp::socket 之间没有共享基类。

我将如何创建一个封装网络语义的连接,以便其他代码不必处理所使用协议的细节?

IE 我想实现类似的东西:

class Connection() {
  Connection(ip::tcp::endpoint& ep);
  Connection(local::stream_protocol::endpoint& ep);

  void send(Buffer& buf);
}

我将如何实现这一点?

Developing a network application, I have a Connection class that manages sending and receiving messages on the network. I'm using boost::asio.

I now want to let the Connection class handle connections both over TCP, and over local UNIX stream sockets. However, the template-design of boost confuses me. AFAICT, there's no shared base-class between local::stream_protocol::socket and ip::tcp::socket.

How would I go about creating a Connection that encapsulates the network-semantics such that other code don't have to deal with the details of what protocol is used?

I.E. I want to implemented something like:

class Connection() {
  Connection(ip::tcp::endpoint& ep);
  Connection(local::stream_protocol::endpoint& ep);

  void send(Buffer& buf);
}

How would I achieve this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

地狱即天堂 2025-01-15 17:03:53

经过一番思考,我目前的解决方案是将Connection的send和recv函数虚拟化,并创建一个Connection的模板子类,大致是:

template <typename Protocol>
class ConnectionImpl : public Connection {
    typedef typename Protocol::socket Socket;
    typedef typename Protocol::endpoint EndPoint;

    Socket _socket;
public:
    ConnectionImpl(boost::asio::io_service& ioSvc, const EndPoint& addr) 
        : Connection(ioSvc), _socket(ioSvc) { 
        _socket.connect(addr);
    }

    void trySend() {
        // Initiate async send on _socket here
    }

    void tryRead() {
        // Initiate async recv on _socket here
    }
}

有没有办法避免是否需要子类化和使用虚函数?

After some pondering, my current solution is to make the send and recv functions of Connection virtual, and create a template-subclass of Connection, roughly:

template <typename Protocol>
class ConnectionImpl : public Connection {
    typedef typename Protocol::socket Socket;
    typedef typename Protocol::endpoint EndPoint;

    Socket _socket;
public:
    ConnectionImpl(boost::asio::io_service& ioSvc, const EndPoint& addr) 
        : Connection(ioSvc), _socket(ioSvc) { 
        _socket.connect(addr);
    }

    void trySend() {
        // Initiate async send on _socket here
    }

    void tryRead() {
        // Initiate async recv on _socket here
    }
}

Is there a way to avoid the need to subclass and use of virtual functions?

留一抹残留的笑 2025-01-15 17:03:53

AFAICT,之间没有共享基类
local::stream_protocol::socket 和 ip::tcp::socket。

所有套接字对象都没有明确地指定基类,文档很好地描述了原理

不包括 BSD 套接字 API 的不安全和容易出错的方面。为了
例如,使用 int 来表示所有套接字就缺乏类型安全性。
Boost.Asio 中的套接字表示对每个套接字使用不同的类型
协议,例如对于 TCP,使用 ip::tcp::socket,对于 UDP,使用 ip::tcp::socket
使用 ip::udp::socket

AFAICT, there's no shared base-class between
local::stream_protocol::socket and ip::tcp::socket.

There is explicitly no base class for all socket objects on purpose, the documentation describes the rationale quite well

Unsafe and error prone aspects of the BSD socket API not included. For
example, the use of int to represent all sockets lacks type safety.
The socket representation in Boost.Asio uses a distinct type for each
protocol, e.g. for TCP one would use ip::tcp::socket, and for UDP one
uses ip::udp::socket

习惯成性 2025-01-15 17:03:53

请改用 boost::asio:generic::stream_protocol::socket 。当您调用 async_connect()/connect() 时,它将从远程端点提取系列和协议,然后将它们传递给 socket() 系统调用以创建正确的套接字。

boost::asio::generic::stream_protocol::socket socket_{io_service};

if (use_unix_socket) {
    boost::asio::local::stream_protocol::endpoint unix_endpoint{"/tmp/socketpath.sock"};
    socket_.async_connect(unix_endpoint, [](boost::system::error_code ec){

    }};
}
else {
    boost::asio::ip::tcp::endpoint tcp_endpoint{...};
    socket_.async_connect(tcp_endpoint, [](boost::system::error_code ec){

    }};
}

还有来自 boost::asio::basic_socket 的代码:

template <typename ConnectHandler>
  BOOST_ASIO_INITFN_RESULT_TYPE(ConnectHandler,
      void (boost::system::error_code))
  async_connect(const endpoint_type& peer_endpoint,
      BOOST_ASIO_MOVE_ARG(ConnectHandler) handler)
  {
    // If you get an error on the following line it means that your handler does
    // not meet the documented type requirements for a ConnectHandler.
    BOOST_ASIO_CONNECT_HANDLER_CHECK(ConnectHandler, handler) type_check;

    if (!is_open())
    {
      boost::system::error_code ec;
      const protocol_type protocol = peer_endpoint.protocol();
      if (this->get_service().open(this->get_implementation(), protocol, ec))
      {
        detail::async_result_init<
          ConnectHandler, void (boost::system::error_code)> init(
            BOOST_ASIO_MOVE_CAST(ConnectHandler)(handler));

        this->get_io_service().post(
            boost::asio::detail::bind_handler(
              BOOST_ASIO_MOVE_CAST(BOOST_ASIO_HANDLER_TYPE(
                ConnectHandler, void (boost::system::error_code)))(
                  init.handler), ec));

        return init.result.get();
      }
    }

    return this->get_service().async_connect(this->get_implementation(),
        peer_endpoint, BOOST_ASIO_MOVE_CAST(ConnectHandler)(handler));
  }

Use boost::asio:generic::stream_protocol::socket instead. When you call async_connect()/connect(), it will extract the family and protocol from the remote endpoint and then pass them to the socket() syscall to create the correct socket.

boost::asio::generic::stream_protocol::socket socket_{io_service};

if (use_unix_socket) {
    boost::asio::local::stream_protocol::endpoint unix_endpoint{"/tmp/socketpath.sock"};
    socket_.async_connect(unix_endpoint, [](boost::system::error_code ec){

    }};
}
else {
    boost::asio::ip::tcp::endpoint tcp_endpoint{...};
    socket_.async_connect(tcp_endpoint, [](boost::system::error_code ec){

    }};
}

And there is the code from boost::asio::basic_socket:

template <typename ConnectHandler>
  BOOST_ASIO_INITFN_RESULT_TYPE(ConnectHandler,
      void (boost::system::error_code))
  async_connect(const endpoint_type& peer_endpoint,
      BOOST_ASIO_MOVE_ARG(ConnectHandler) handler)
  {
    // If you get an error on the following line it means that your handler does
    // not meet the documented type requirements for a ConnectHandler.
    BOOST_ASIO_CONNECT_HANDLER_CHECK(ConnectHandler, handler) type_check;

    if (!is_open())
    {
      boost::system::error_code ec;
      const protocol_type protocol = peer_endpoint.protocol();
      if (this->get_service().open(this->get_implementation(), protocol, ec))
      {
        detail::async_result_init<
          ConnectHandler, void (boost::system::error_code)> init(
            BOOST_ASIO_MOVE_CAST(ConnectHandler)(handler));

        this->get_io_service().post(
            boost::asio::detail::bind_handler(
              BOOST_ASIO_MOVE_CAST(BOOST_ASIO_HANDLER_TYPE(
                ConnectHandler, void (boost::system::error_code)))(
                  init.handler), ec));

        return init.result.get();
      }
    }

    return this->get_service().async_connect(this->get_implementation(),
        peer_endpoint, BOOST_ASIO_MOVE_CAST(ConnectHandler)(handler));
  }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文