第一条消息后,来自ASIO SSL服务器代码的Gibberish

时间:2012-03-10 12:03:56

标签: ssl boost-asio

我正在尝试使用来自here的Boost ASIO示例代码编写基于SSL的异步服务器。

我在客户端正确获取第一条消息及其响应。然后,我发送第二条消息,该消息在服务器上收到,但是当响应被发送到客户端时。它有点胡言乱语。

我已将服务器代码上传到pastebin。另外,请在下面找到:

// file  -  Server.h
  class Server
  {
  public:
    explicit Server(const std::string &address,
               int port,
               std::size_t threadPoolSize);

    // run the io_service loop
    void run();

    // stop the server
    void stop();

  private:
    //handle async accept operation
    void handleAccept(const boost::system::error_code &e);

    // number of threads in thread pool
    std::size_t _threadPoolSize;

    // the io_service
    boost::asio::io_service _ioService;

    // acceptor to listen for incoming connections
    boost::asio::ip::tcp::acceptor _acceptor;

    std::string get_password()
    {
      return "password";
    }

    // ssl context
    boost::asio::ssl::context _context;    
    ConnectionPtr _connection;

  };

//////////////////////////////////////////////////////////////////////////
// file  -  Server.cpp
//////////////////////////////////////////////////////////////////////////
  Server::Server(const std::string& address,
               int port,
               std::size_t threadPoolSize)
    : _threadPoolSize(threadPoolSize),
      _acceptor(_ioService),
      _context(_ioService, boost::asio::ssl::context::sslv23),
      _connection()
  {
    try {
      DEBUG_2("Starting server on port: ", port);
      boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::tcp::v4(), port);
      _acceptor.open(endpoint.protocol());
      _acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
      _acceptor.bind(endpoint);
      _acceptor.listen();
      _context.set_options(
        boost::asio::ssl::context::default_workarounds
        | boost::asio::ssl::context::no_sslv2
        | boost::asio::ssl::context::single_dh_use);
      _context.set_password_callback(boost::bind(&Server::get_password, this));
      _context.use_certificate_chain_file("./demoCA/cacert.pem");
      _context.use_private_key_file("./demoCA/private/cakey.pem", 
                                    boost::asio::ssl::context::pem);
      // _context.use_tmp_dh_file("dh512.pem");
      _connection.reset(new CclConnection(_ioService, _context));
      _acceptor.async_accept(_connection->socket(),
                             boost::bind(&Server::handleAccept, 
                                         this,
                                         boost::asio::placeholders::error));
    }
    catch(std::exception& e)
    {
      STD_EXCEPTION_MESSAGE;
      throw;
    }

  }

  void Server::run()
  {
    // Create a pool of threads to run all of the io_services.
    std::vector<boost::shared_ptr<boost::thread> > threads;
    for (std::size_t i = 0; i < _threadPoolSize; ++i)
    {
      boost::shared_ptr<boost::thread> 
    thread(new boost::thread(
         boost::bind(&boost::asio::io_service::run, 
                 &_ioService)
         )
      );
      threads.push_back(thread);
    }

    // Wait for all threads in the pool to exit.
    for (std::size_t i = 0; i < threads.size(); ++i)
      threads[i]->join();
  }

  void Server::stop()
  {
    _ioService.stop();
  }

  void Server::handleAccept(const boost::system::error_code& e)
  {
    if (!e)
    {
      _connection->handshake();
      _connection.reset(new CclConnection(_ioService, _context));
      _acceptor.async_accept(_connection->socket(),
                 boost::bind(&Server::handleAccept, 
                     this,
                     boost::asio::placeholders::error));
    }
  }

////////////////////////////////////////////////////////////
// file  -  Connection.h
////////////////////////////////////////////////////////////

#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>

  typedef boost::asio::ssl::stream< boost::asio::ip::tcp::socket >
    ssl_socket;

  class Connection 
    : public boost::enable_shared_from_this<Connection>
  {
  public:
    explicit Connection(boost::asio::io_service& io_service,
                           boost::asio::ssl::context& context);

    //get socket from the connection
    ssl_socket::lowest_layer_type& socket();

    // do an SSL handshake
    void handshake();

    //get socket from the connection
    boost::asio::io_service::strand& strand();

    // start first async operation
    void start();

    void sendResponse(const Response& response);

    void close();

    // get remote IP address for this connection
    std::string getIPAddress();

  private:
    void handleRead(const boost::system::error_code& e,
            std::size_t bytesTransferred);

    void handleWrite(const boost::system::error_code& e);

    boost::asio::io_service::strand _strand;

    ssl_socket _socket;

    void handleHandshake(const boost::system::error_code& e);

    boost::array<char, 8192> _buffer;
  };

  typedef boost::shared_ptr<Connection> ConnectionPtr;

///////////////////////////////////////////////////////////////
// File - Connection.cpp
///////////////////////////////////////////////////////////////


  Connection::Connection(boost::asio::io_service& io_service,
                               boost::asio::ssl::context& context)
    : _strand(io_service),
      _socket(io_service, context)
  {
  }

  ssl_socket::lowest_layer_type& Connection::socket()
  {
    return _socket.lowest_layer();
  }

  boost::asio::io_service::strand& Connection::strand()
  {
    return _strand;
  }

  void Connection::start()
  {
    _socket.async_read_some(boost::asio::buffer(_buffer),
                _strand.wrap(
                  boost::bind(
                &Connection::handleRead,
                shared_from_this(),
                boost::asio::placeholders::error,
                boost::asio::placeholders::bytes_transferred
                )
                  )
      );
  }

  void Connection::handshake()
  {
    std::cout << "doing ssl handshake" << std::endl;
    _socket.async_handshake(boost::asio::ssl::stream_base::server,
                            _strand.wrap(
                              boost::bind(
                                &Connection::handleHandshake,
                                shared_from_this(),
                                boost::asio::placeholders::error
                                )
                              )
      );
  }

  void Connection::handleHandshake(const boost::system::error_code& error)
  {
    if (!error)
    {
      _socket.async_read_some(boost::asio::buffer(_buffer),
                              _strand.wrap(
                                boost::bind(
                                  &Connection::handleRead,
                                  shared_from_this(),
                                  boost::asio::placeholders::error,
                                  boost::asio::placeholders::bytes_transferred
                                  )
                                )
        );
    }
    else
    {
      std::cout << "error occured: " << error.message();
      this->close();
    }
  }

  void Connection::handleRead(const boost::system::error_code& e,
                 std::size_t bytesTransferred)
  {
    if (!e) {

      // handle read data
      this->start();
    }
    else {
      this->close();
    }
  }

  void Connection::handleWrite(const boost::system::error_code& e)
  {
    if (!e) {
       this->start();
    }
    else {
      this->close();
    }
  }

  void Connection::sendResponse(const Response& response)
  {
    boost::asio::async_write(_socket,
                             boost::asio::buffer(convertToString(response)),
                             _strand.wrap(
                               boost::bind(
                                 &Connection::handleWrite,
                                 shared_from_this(),
                                 boost::asio::placeholders::error
                                 )
                               )
      );

  }

  void Connection::close()
  {
    boost::system::error_code ignoredCode;
    socket().shutdown(boost::asio::ip::tcp::socket::shutdown_both,
                     ignoredCode);
  }

  std::string Connection::getIPAddress()
  {
    return socket().remote_endpoint().address().to_string();
  }

有人能指出我在这里做错了什么吗?

更新:我在评论中指出问题已得到解决。该问题与stackoverflow上的另一个old question完全相似。

1 个答案:

答案 0 :(得分:2)

您的代码无法识别,boost::asio::buffer只是构建它的对象包装器。 在这里(Connection::sendResponse):

boost::asio::buffer(convertToString(response))

您在(可能)临时对象中创建了缓冲区,boost::asio::async_write使用之前已被销毁

段落“缓冲区失效”

中的

Boost.Asio documentation specifically tells you about that

  

对于接受类型参数的boost :: asio :: buffer重载   std :: string,返回的缓冲区对象根据无效   为引用,指针和引号的无效定义的规则   迭代器引用序列的元素(C ++ Std,21.3)。