可重载的boost :: asio :: basic_stream_socket

时间:2012-02-25 10:05:07

标签: c++ templates boost-asio generic-programming

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

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

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

即。我想实现类似的东西:

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

  void send(Buffer& buf);
}

我将如何实现这一目标?

3 个答案:

答案 0 :(得分:1)

经过一番思考,我目前的解决方案是使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
    }
}

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

答案 1 :(得分:1)

  

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

有意为所有套接字对象明确没有基类,documentation很好地描述了基本原理

  

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

答案 2 :(得分:1)

请改用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));
  }