Перегрузка наддува :: asio :: basic_stream_socket - PullRequest
2 голосов
/ 25 февраля 2012

Разрабатывая сетевое приложение, у меня есть класс Connection, который управляет отправкой и получением сообщений в сети. Я использую boost :: asio.

Теперь я хочу, чтобы класс Connection обрабатывал соединения как через TCP, так и через локальные потоковые сокеты UNIX. Однако шаблон-дизайн boost меня смущает. AFAICT, между local :: stream_protocol :: socket и ip :: tcp :: socket нет общего базового класса.

Как бы я мог создать соединение, инкапсулирующее семантику сети, чтобы другой код не сталкивался с деталями используемого протокола?

т.е. Я хочу реализовать что-то вроде:

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

  void send(Buffer& buf);
}

Как бы мне этого добиться?

Ответы [ 3 ]

1 голос
/ 26 февраля 2012

AFAICT, нет общего базового класса между local :: stream_protocol :: socket и ip :: tcp :: socket.

Специально не существует базового класса для всех объектов сокетов, документация достаточно хорошо описывает обоснование

Небезопасные и подверженные ошибкам аспекты API сокетов BSD не включены. За Например, использование int для представления всех сокетов лишено безопасности типов. Представление сокета в Boost.Asio использует отдельный тип для каждого протокол, например для TCP можно использовать ip :: tcp :: socket, а для UDP один использует ip :: udp :: socket

1 голос
/ 05 октября 2015

Вместо этого используйте 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));
  }
1 голос
/ 25 февраля 2012

После некоторых размышлений мое текущее решение состоит в том, чтобы сделать функции send и recv Connection виртуальными, и создать шаблон-подкласс 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
    }
}

Есть ли способчтобы избежать необходимости создавать подклассы и использовать виртуальные функции?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...