簡體   English   中英

在udp socket上增強asio多個async_send

[英]boost asio multiple async_send on udp socket

在boost :: asio中使用fire和忘記接近udp套接字是否安全?

所以,例如,如果我有這樣的代碼

 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個數據包?

不,這肯定是不安全的, 沒有任何的ASIO async_ *函數的文檔是“發射后不管”。

basic_datagram_socket :: async_send緩沖區的boost asio引用指出:“盡管可以根據需要復制buffers對象,但調用者仍保留底層內存塊的所有權,這必須保證它們在調用處理程序之前保持有效。”

如果您需要“一勞永逸”的方法,那么您需要一個類來管理您的連接並為您緩沖數據包。 以下是使用deque緩沖數據包的示例:

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();
  }
};

不能保證僅僅因為底層協議不能保證。

只要在socket.async_send()期間提供給緩沖區的底層內存在socket.async_send()處理程序之前保持有效,並且沒有其他線程對socket進行並發調用,那么socket.async_send()的條件已經滿足,它應該是安全。


對於實現細節, basic_datagram_socket::async_send()將使其服務創建單個非組合操作( reactive_socket_send_opwin_iocp_socket_send_op )。 然后該服務將使其reactor啟動操作。 某些反應堆實施可能會嘗試立即運行該操作; 否則,基於操作類型(讀或寫)將操作添加到特定於套接字文件描述符的隊列。 操作隊列允許對給定文件描述符進行多次讀取或寫入操作。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM