c++ - 如何为 Boost.Asio 设计自定义 IO 对象

标签 c++ boost boost-asio

我有一个代表嵌入式设备的基类 (DeviceBase),我想与之通信。该设备可以通过多种方式访问​​,包括 USB 和 TCP 套接字。此外,还有一个适用于文件的模拟实现。

到现在为止,我只使用了同步读/写调用,所有的实现都只是从基类派生的类,覆盖了读/写函数。这使我能够使用多态指针和容器为应用程序逻辑提供对设备的独立于实现的访问。

现在我想使用 Boost.Asio 来启用简单的异步 IO。 我找到了这个指南 http://www.highscore.de/cpp/boost/asio.html描述了如何编写您自己的扩展,但它非常简单,而且我偶然发现了一些在那里没有讨论的问题。

  • 目前,我所有的实现都有不同的构造函数(显然,因为寻址/初始化设备连接的方式不同)。指南中的实现类是由io_service构造的,这意味着用户不能向构造函数传递参数。

  • 指南中的示例以custom_io_object<implementation> 的形式提供了一个模板类。 ,这将阻止使用多态指针,因为现在不同类型的 IO 对象没有公共(public)基类。

是否有任何形式的文档或书籍讨论 Boost.Asio 扩展的设计? 我是否忽略了什么?

最佳答案

听起来基于继承的解决方案可能更适合您。

下面是一个示例基类,它使用 boost::signals2 来指示接收到的消息:

class Connection
{
public:

  typedef boost::signals2::signal<void (const std::vector<char>&)>
     PacketReceived;

protected:
  PacketReceived packet_received_;
  size_t max_rx_packet_size_;
  std::vector<char> read_buffer_;
  std::deque<std::vector<char> > tx_queue_;

  void read_handler(boost::system::error_code const& error,
                    size_t bytes_transferred)
  {
    if (boost::asio::error::operation_aborted != error)
    {
      if (error)
        ; // TODO handle the error, it may be a disconnect.
      else
      {
        read_buffer_.resize(bytes_transferred);
        packet_received_(read_buffer_);
        enable_reception(max_rx_packet_size_);
      }
    }
  }

  void write_handler(boost::system::error_code const& error,
                     size_t bytes_transferred)
  {
    if (boost::asio::error::operation_aborted != error)
    {
      tx_queue_.pop_front();
      if (error)
        ; // TODO handle the error, it may be a disconnect.
      else
        if (!tx_queue_.empty())
          transmit();
    }
  }

  virtual void receive() = 0;

  virtual void transmit() = 0;

  explicit Connection() :
    packet_received_(),
    max_rx_packet_size_(),
    read_buffer_(),
    tx_queue_()
  {}

public:

  virtual void close() = 0;

  virtual ~Connection()
  {}

  void connectPacketReceived(const PacketReceived::slot_type& slot)
  { packet_received_.connect(slot); }

  void enable_reception(size_t max_rx_packet_size)
  {
    max_rx_packet_size_ = max_rx_packet_size;
    receive();
  }

  const std::vector<char>& read_buffer() const
  { return read_buffer_; }

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

下面是实现 SSL 套接字的类的概要:

class SslConnection :
    public Connection,
    public boost::enable_shared_from_this<SslConnection>
{
  boost::asio::ssl::stream<boost::asio::ip::tcp::socket> ssl_socket_;

  virtual void receive()
  {
    ssl_socket_.async_read_some(boost::asio::buffer(read_buffer_),
         boost::bind(&SslConnection::read_handler, shared_from_this(),
                     boost::asio::placeholders::error,
                     boost::asio::placeholders::bytes_transferred));
  }

  virtual void transmit()
  {
    boost::asio::async_write(ssl_socket_,
                             boost::asio::buffer(tx_queue_.front()),
         boost::bind(&SslConnection::write_handler, shared_from_this(),
                     boost::asio::placeholders::error,
                     boost::asio::placeholders::bytes_transferred));
  }

  SslConnection(boost::asio::io_service&   io_service,
                boost::asio::ssl::context& ssl_context) :
    Connection(),
    ssl_socket_(io_service, ssl_context)
  {}

public:

  static boost::shared_ptr<SslConnection> create
                     (boost::asio::io_service&   io_service,
                      boost::asio::ssl::context& ssl_context)
  {
    return boost::shared_ptr<SslConnection>
        (new SslConnection(io_service, ssl_context));
  }

  virtual void close()
  {
    boost::system::error_code ignoredEc;
    ssl_socket_.lowest_layer().close(ignoredEc);
  }
};

关于c++ - 如何为 Boost.Asio 设计自定义 IO 对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19633085/

相关文章:

ios - iPhone在不同端口上意外复制TCP数据包

c++ - 从类型列表到参数包

c++ - 用C++查找文件大小

c++ - 在集合中寻找一个值

c++ - 使用 Boost.Preprocessor 来减少代码重复

c++ - boost::asio::async_read_some在父线程中运行

c++ - 使用终端链接 boost::asio

C++类与函数,构造函数中的引用参数

c++ - std::map 覆盖错误的键

c++ - 为什么编译器会在某些优化级别警告未初始化的边迭代器?