简体   繁体   English

在udp socket上增强asio多个async_send

[英]boost asio multiple async_send on udp socket

Is it safe to have fire and forget approach to udp socket in boost::asio? 在boost :: asio中使用fire和忘记接近udp套接字是否安全?

so eg if i have such code 所以,例如,如果我有这样的代码

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

am i guaranteed that this will not fail - that means that at the receiving endpoint i will get 4 packets containing somedata1,somedata2,somedata3,somedata4 ? 我保证这不会失败 - 这意味着在接收端点我将获得包含somedata1,somedata2,somedata3,somedata4的4个数据包?

No, it most certainly isn't safe, none of the asio async_* functions are documented to be "fire and forget". 不,这肯定是不安全的, 没有任何的ASIO async_ *函数的文档是“发射后不管”。

The boost asio reference for the basic_datagram_socket::async_send buffers states: “Although the buffers object may be copied as necessary, ownership of the underlying memory blocks is retained by the caller, which must guarantee that they remain valid until the handler is called.” basic_datagram_socket :: async_send缓冲区的boost asio引用指出:“尽管可以根据需要复制buffers对象,但调用者仍保留底层内存块的所有权,这必须保证它们在调用处理程序之前保持有效。”

If you need a "fire and forget" approach, then you'll need to a class to manage your connection and buffer the packets for you. 如果您需要“一劳永逸”的方法,那么您需要一个类来管理您的连接并为您缓冲数据包。 Here's an example using a deque to buffer the packets: 以下是使用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();
  }
};

There is no guarantee simply because the underlying protocol makes no guarantee. 不能保证仅仅因为底层协议不能保证。

As long as the underlying memory provided to buffer during socket.async_send() remains valid until the handler is called, and no other thread is making concurrent calls to socket , then the criteria for socket.async_send() has been satisfied and it should be safe. 只要在socket.async_send()期间提供给缓冲区的底层内存在socket.async_send()处理程序之前保持有效,并且没有其他线程对socket进行并发调用,那么socket.async_send()的条件已经满足,它应该是安全。


For implementation details, the basic_datagram_socket::async_send() will have its service create a single non-composed operation ( reactive_socket_send_op or win_iocp_socket_send_op ). 对于实现细节, basic_datagram_socket::async_send()将使其服务创建单个非组合操作( reactive_socket_send_opwin_iocp_socket_send_op )。 The service will then have its reactor start the operation. 然后该服务将使其reactor启动操作。 Some reactor implementations may attempt to run the operation immediately; 某些反应堆实施可能会尝试立即运行该操作; otherwise, the operation is added to a queue specific to the socket file descriptor based on the operation type (read or write). 否则,基于操作类型(读或写)将操作添加到特定于套接字文件描述符的队列。 The operation queues allow for multiple read or write operations to be outstanding for a given file descriptor. 操作队列允许对给定文件描述符进行多次读取或写入操作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM