2013-10-28 66 views
4

在boost :: asio中有沒有安全的方法來使用udp套接字?在udp套接字上增加asio多個async_send

所以e.g如果我有這樣的代碼

socket.async_send(buffer(somedata1),write_handler); 
socket.async_send(buffer(somedata2),write_handler); 
socket.async_send(buffer(somedata3),write_handler); 
socket.async_send(buffer(somedata4),write_handler); 

我保證,這不會失敗 - 這意味着在接收端點,我會得到一個包含somedata1,somedata2,somedata3,somedata4 4個包?

回答

2

誰也不能保證完全是因爲底層協議不作任何保證。

只要提供在socket.async_send()緩衝底層的內存仍然有效,直到處理程序被調用,並沒有其他線程來socket進行併發呼叫,然後socket.async_send()條件已經滿足,它應該是安全的。


對於實施細節,但basic_datagram_socket::async_send()將其服務建立一個單一的非由操作(reactive_socket_send_opwin_iocp_socket_send_op)。該服務然後將其reactor開始操作。一些反應堆實施可能會嘗試立即運行該操作;否則,根據操作類型(讀或寫)將操作添加到特定於套接字文件描述符的隊列中。對於給定的文件描述符,操作隊列允許多個讀或寫操作未完成。

4

不,它肯定是不安全的,沒有 asio async_ *函數被記錄爲「fire and forget」。

basic_datagram_socket::async_send緩衝區的boost asio引用聲明:「雖然可以根據需要複製緩衝區對象,但調用者會保留底層內存塊的所有權,這必須保證它們在調用處理程序之前保持有效。 「

如果您需要一種」消除遺忘「的方法,那麼您需要一個班級來管理您的連接併爲您緩衝數據包。下面是一個使用雙端隊列來緩衝包的例子:

class Connection : public boost::enable_shared_from_this<Connection> 
{ 
    boost::asio::ip::udp::socket socket_; 
    std::deque<std::vector<char> > tx_queue_; 

    /// transmit the packet at the head of the queue 
    void transmit() 
    { 
    socket_.async_send(
     boost::asio::buffer(&tx_queue_.front()[0], tx_queue_.front().size()), 
     boost::bind(&Connection::write_callback, 
        boost::weak_ptr<Connection>(shared_from_this()), 
        boost::asio::placeholders::error, 
        boost::asio::placeholders::bytes_transferred)); 
    } 

    /// The function called whenever a write event is received. 
    void write_handler(boost::system::error_code const& error, 
        size_t /* bytes_transferred */) 
    { 
    tx_queue_.pop_front(); 
    if (error) 
     ; // handle the error, it may be a disconnect. 
    else 
     if (!tx_queue_.empty()) 
     transmit(); 
    } 

    /// Static callback function. 
    /// It ensures that the object still exists and the event is valid 
    /// before calling the write handler. 
    static void write_callback(boost::weak_ptr<Connection> ptr, 
          boost::system::error_code const& error, 
          size_t bytes_transferred) 
    { 
    boost::shared_ptr<Connection> pointer(ptr.lock()); 
    if (pointer && (boost::asio::error::operation_aborted != error)) 
     pointer->write_handler(error, bytes_transferred); 
    } 

    /// Private constructor to enusure the class is created as a shared_ptr. 
    explicit Connection(boost::asio::io_service& io_service) : 
    socket_(io_service), 
    tx_queue_() 
    {} 

public: 

    /// Factory method to create an instance of this class. 
    static boost::shared_ptr<Connection> create(boost::asio::io_service& io_service) 
    { return boost::shared_ptr<Connection>(new Connection(io_service)); } 

    /// Destructor, closes the socket to cancel the write callback 
    /// (by calling it with error = boost::asio::error::operation_aborted) 
    /// and free the weak_ptr held by the call to bind in the transmit function. 
    ~Connection() 
    { socket_.close(); } 

    /// add the packet to the end of the queue and send it ASAP. 
#if defined(BOOST_ASIO_HAS_MOVE) 
    void send(std::vector<char>&& packet) 
#else 
    void send(const std::vector<char>& packet) 
#endif 
    { 
    bool queue_empty(tx_queue_.empty()); 
    tx_queue_.push_back(packet); 
    if (queue_empty) 
     transmit(); 
    } 
}; 
+0

謝謝@Igor,我沒有意識到任何'async \ _ *'函數都可以。你明顯比我有更好的asio內部知識。 我已經編輯了我的答案,將要記錄的行更改爲「fire and forget」,並將其引用到異步緩衝區的asio文檔。 所以這種方式是不可爭論的,我們都是對的! ;) – kenba