Нужно объяснить, чтобы понять asio REFERENCE_COUNTED пример - PullRequest
3 голосов
/ 19 февраля 2012

Образец, который я смотрю в полном объеме:

#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/shared_ptr.hpp>
#include <iostream>
#include <vector>

using boost::asio::ip::tcp;

// A reference-counted non-modifiable buffer class.
class shared_const_buffer
{
public:
  // Construct from a std::string.
  explicit shared_const_buffer(const std::string& data)
    : data_(new std::vector<char>(data.begin(), data.end())),
      buffer_(boost::asio::buffer(*data_))
  {
  }
  // Implement the ConstBufferSequence requirements.
  typedef boost::asio::const_buffer value_type;
  typedef const boost::asio::const_buffer* const_iterator;
  const boost::asio::const_buffer* begin() const { return &buffer_; }
  const boost::asio::const_buffer* end() const { return &buffer_ + 1; }

private:
  boost::shared_ptr<std::vector<char> > data_;
  boost::asio::const_buffer buffer_;
};

class session
  : public boost::enable_shared_from_this<session>
{
public:
  session(boost::asio::io_service& io_service)
    : socket_(io_service)
  {
  }

  tcp::socket& socket()
  {
    return socket_;
  }

  void start()
  {
    using namespace std; // For time_t, time and ctime.
    time_t now = time(0);
    shared_const_buffer buffer(ctime(&now));
    boost::asio::async_write(socket_, buffer,
        boost::bind(&session::handle_write, shared_from_this()));
  }

  void handle_write()
  {
  }

private:
  // The socket used to communicate with the client.
  tcp::socket socket_;
};

typedef boost::shared_ptr<session> session_ptr;

class server
{
public:
  server(boost::asio::io_service& io_service, short port)
    : io_service_(io_service),
      acceptor_(io_service, tcp::endpoint(tcp::v4(), port))
  {
    session_ptr new_session(new session(io_service_));
    acceptor_.async_accept(new_session->socket(),
        boost::bind(&server::handle_accept, this, new_session,
          boost::asio::placeholders::error));
  }

  void handle_accept(session_ptr new_session,
      const boost::system::error_code& error)
  {
    if (!error)
    {
      new_session->start();
    }

    new_session.reset(new session(io_service_));
    acceptor_.async_accept(new_session->socket(),
        boost::bind(&server::handle_accept, this, new_session,
          boost::asio::placeholders::error));
  }

private:
  boost::asio::io_service& io_service_;
  tcp::acceptor acceptor_;
};

int main(int argc, char* argv[])
{
  try
  {
    if (argc != 2)
    {
      std::cerr << "Usage: reference_counted <port>\n";
      return 1;
    }

    boost::asio::io_service io_service;

    using namespace std; // For atoi.
    server s(io_service, atoi(argv[1]));

    io_service.run();
  }
  catch (std::exception& e)
  {
    std::cerr << "Exception: " << e.what() << "\n";
  }

  return 0;
}

Я Java-программист, пытающийся понять, как работает boost asio, есть некоторые моменты, с которыми мне нужна помощь. Мои вопросы:

  1. В этих строках:

    const boost::asio::const_buffer* begin() const { return &buffer_; }
    const boost::asio::const_buffer* end() const { return &buffer_ + 1; }
    

    этот shared_const_buffer используется для async_write позже, поэтому я думаю, что он должен реализовывать некоторый буфер, но я не вижу никакой наследуемой подписи. Так определить begin() и end() достаточно?

  2. И в этих строках:

    shared_const_buffer buffer(ctime(&now));
    boost::asio::async_write(socket_, buffer, 
                             boost::bind(&session::handle_write, 
                                         shared_from_this()));    
    

    share_const_buffer имеет data_ является общим указателем, но не сам по себе, как действует buffer до тех пор, пока async_write фактически не запишет данные?

1 Ответ

1 голос
/ 19 февраля 2012

это shared_const_buffer полезно для async_write() позже, так что я думаю это должен реализовать какой-то буфер, но я не вижу наследства подпись. Так что определить begin() и end() достаточно?

Буфер, используемый классом shared_const_buffer, является его _data членом, a boost::shared_ptr<std::vector<char> >. Выставления итераторов в буфер достаточно для его использования с async_write().

share_const_buffer имеет data_ общий указатель, но не сам, как буфер действителен до тех пор, пока async_write() фактически не записывает данные?

Класс shared_const_buffer реализует требования типа asio ConstBufferSequence

  // Implement the ConstBufferSequence requirements.
  typedef boost::asio::const_buffer value_type;
  typedef const boost::asio::const_buffer* const_iterator;
  const boost::asio::const_buffer* begin() const { return &buffer_; }
  const boost::asio::const_buffer* end() const { return &buffer_ + 1; }

поэтому при вызове async_write оно копируется, в документации прямо указывается следующее:

буферы

Один или несколько буферов, содержащих данные для записи. Хотя объект буферов может быть скопирован по мере необходимости, право собственности на базовые блоки памяти сохраняются вызывающей стороной, которая должна гарантировать, что они остаются действительными, пока не будет вызван обработчик.

Однако исходные данные не копируются, поскольку они сохраняются в shared_ptr. Это можно увидеть, посыпав несколько операторов отладки

--- reference_counted.cpp   2012-02-19 08:30:32.000000000 -0600
+++ reference_counted_good.cpp  2012-02-19 08:26:27.000000000 -0600
@@ -26,9 +26,7 @@
     : data_(new std::vector<char>(data.begin(), data.end())),
       buffer_(boost::asio::buffer(*data_))
   {
-      std::cout << "shared_const_buffer()" << std::endl;
   }
-  ~shared_const_buffer() { std::cout << "~shared_const_buffer() buffer use count: " << data_.use_count() << std::endl; }

   // Implement the ConstBufferSequence requirements.
   typedef boost::asio::const_buffer value_type;
@@ -66,7 +64,6 @@

   void handle_write()
   {
-      std::cout << "handle_write" << std::endl;
   }

 private:

и работает

Sam-Millers-MacBook-Pro:stackoverflow samm$ ./a.out 1234
shared_const_buffer()
~shared_const_buffer() buffer use count: 8
~shared_const_buffer() buffer use count: 7
~shared_const_buffer() buffer use count: 6
~shared_const_buffer() buffer use count: 5
~shared_const_buffer() buffer use count: 4
~shared_const_buffer() buffer use count: 3
~shared_const_buffer() buffer use count: 3
~shared_const_buffer() buffer use count: 2
handle_write
~shared_const_buffer() buffer use count: 2
~shared_const_buffer() buffer use count: 1

в другой оболочке

Sam-Millers-MacBook-Pro:stackoverflow samm$ telnet localhost 1234
Trying ::1...
telnet: connect to address ::1: Connection refused
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Sun Feb 19 08:22:56 2012
Connection closed by foreign host.
Sam-Millers-MacBook-Pro:stackoverflow samm$ 

Таким образом, фактический буфер остается действительным до тех пор, пока последний shared_const_buffer не выйдет из области видимости и не запустит дескриптор

...