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

时间:2013-10-28 11:05:32

标签: 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对象没有共同的基类。

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

1 个答案:

答案 0 :(得分:2)

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

以下是使用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);
  }
};