2012-02-25 117 views
2

開發一個網絡應用程序,我有一個Connection類來管理網絡上的發送和接收消息。我正在使用boost :: asio。超負荷提升:: asio :: basic_stream_socket

我現在想讓Connection類通過TCP和本地UNIX流套接字處理連接。然而,boost的模板設計讓我感到困惑。 AFAICT,local :: stream_protocol :: socket和ip :: tcp :: socket之間沒有共享的基類。

我該如何去創建一個封裝網絡語義的連接,以便其他代碼不必處理使用什麼協議的細節?

I.E.我想執行如下:

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

    void send(Buffer& buf); 
} 

我該如何實現這一目標?

回答

1

經過一番琢磨之後,我目前的解決方案是讓Connection虛擬的發送和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

AFAICT, local :: stream_protocol :: socket和ip :: tcp :: socket之間沒有共享基類。

有明確的目的上的所有插座對象沒有基類中,documentation非常好地描述

不安全的和錯誤的BSD套接字API的易發環節未列入的理由。例如,對於 示例,使用int表示所有套接字缺少類型安全性。 Boost.Asio中的套接字表示對於每個 協議使用不同的類型,例如,對於TCP人會使用IP :: TCP ::插座,以及UDP一個 使用IP :: UDP ::插座

+1

謝謝你的鏈接文檔。我錯過了。 也就是說,增強不支持兼容套接字的共享接口有點限制。 I.E.一個流類型的UNIX套接字與TCP套接字具有非常兼容的語義,因此與可能的一個或兩個虛擬函數共享一個基類將會很有用。 – Rawler 2012-03-02 18:06:28

1

使用boost :: ASIO:通用:: stream_protocol ::插座代替。當你調用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){ 

    }}; 
} 

而且有從升壓代碼:: 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)); 
    }