C++ Can';t实现boost::asio::ssl::stream<;boost::asio::ip::tcp::socket>;重新连接到服务器

C++ Can';t实现boost::asio::ssl::stream<;boost::asio::ip::tcp::socket>;重新连接到服务器,c++,sockets,ssl,boost,boost-asio,C++,Sockets,Ssl,Boost,Boost Asio,我需要实现一个处理连接到ssl服务器的类。差不多 基于。然而。没有。所以我 修改如下: boost::asio::ssl::stream<boost::asio::ip::tcp::socket> socket_; /usr/include/boost/asio/impl/read.hpp:271: error: request for member 'async_read_some' in '((boost::asio::detail::read_op<boost::asi

我需要实现一个处理连接到ssl服务器的类。差不多 基于。然而。没有。所以我 修改如下:

boost::asio::ssl::stream<boost::asio::ip::tcp::socket> socket_;
/usr/include/boost/asio/impl/read.hpp:271: error: request for member 'async_read_some' in '((boost::asio::detail::read_op<boost::asio::ssl::stream<boost::asio::basic_stream_socket<boost::asio::ip::tcp> >*, boost::asio::mutable_buffers_1, boost::asio::detail::transfer_all_t, boost::_bi::bind_t<void, boost::_mfi::mf2<void, SSLHandler, const boost::system::error_code&, long unsigned int>, boost::_bi::list3<boost::_bi::value<SSLHandler*>, boost::arg<1> (*)(), boost::arg<2> (*)()> > >*)this)->boost::asio::detail::read_op<boost::asio::ssl::stream<boost::asio::basic_stream_socket<boost::asio::ip::tcp> >*, boost::asio::mutable_buffers_1, boost::asio::detail::transfer_all_t, boost::_bi::bind_t<void, boost::_mfi::mf2<void, SSLHandler, const boost::system::error_code&, long unsigned int>, boost::_bi::list3<boost::_bi::value<SSLHandler*>, boost::arg<1> (*)(), boost::arg<2> (*)()> > >::stream_', which is of pointer type 'boost::asio::ssl::stream<boost::asio::basic_stream_socket<boost::asio::ip::tcp> >*' (maybe you meant to use '->' ?)
          stream_.async_read_some(
          ^

/usr/include/boost/asio/impl/write.hpp:258: error: request for member 'async_write_some' in '((boost::asio::detail::write_op<boost::asio::ssl::stream<boost::asio::basic_stream_socket<boost::asio::ip::tcp> >*, boost::asio::mutable_buffers_1, boost::asio::detail::transfer_all_t, boost::_bi::bind_t<void, boost::_mfi::mf2<void, SSLHandler, const boost::system::error_code&, long unsigned int>, boost::_bi::list3<boost::_bi::value<SSLHandler*>, boost::arg<1> (*)(), boost::arg<2> (*)()> > >*)this)->boost::asio::detail::write_op<boost::asio::ssl::stream<boost::asio::basic_stream_socket<boost::asio::ip::tcp> >*, boost::asio::mutable_buffers_1, boost::asio::detail::transfer_all_t, boost::_bi::bind_t<void, boost::_mfi::mf2<void, SSLHandler, const boost::system::error_code&, long unsigned int>, boost::_bi::list3<boost::_bi::value<SSLHandler*>, boost::arg<1> (*)(), boost::arg<2> (*)()> > >::stream_', which is of pointer type 'boost::asio::ssl::stream<boost::asio::basic_stream_socket<boost::asio::ip::tcp> >*' (maybe you meant to use '->' ?)
          stream_.async_write_some(
          ^
然后我尝试取消对指针的引用以保留旧结构,但出现了新错误:(

boost::asio::async\u connect(*socket.lower\u layer(),mendpointerator,boost::bind(&SSLHandler::handler\u connect,this,boost::asio::placeholders::error));
错误:请求“((SSLHandler*)this)->SSLHandler::socket”中的成员“lower\u layer”,该成员的指针类型为“boost::asio::ssl::stream*”(可能您打算使用“->”?)
boost::asio::async_connect(*socket.lower_layer(),mendpointerator,boost::bind(&SSLHandler::handle_connect,this,boost::asio::placeholders::error))`

请帮忙,我来自java,所以这件事对我来说很复杂。

这是我对Boost 1.66.0中演示的最小更改。请单独在github上查看补丁:

注意:我将地址解析移到了连接序列中,因为如果网络配置已更改,结果可能不同,或者应该首选另一个端点

为此,我们存储了一个
resolver::query query
成员,以便在重新连接时重复查询

这同样有效。您甚至可以决定关闭任何最低级别的连接,以防万一:

auto& ll = socket_.lowest_layer();

if (ll.is_open())
{
  ll.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec);
  //if (ec) std::cout << "socket.shutdown error: " << ec.message() << std::endl;

  ll.close(ec);
  //if (ec) std::cout << "socket.close error: " << ec.message() << std::endl;
}
这显然也有效

下面是相应的补丁:

//
//client.cpp
// ~~~~~~~~~~
//
//版权所有(c)2003-2018克里斯托弗·M·科尔霍夫(克里斯在科尔霍夫网站)
//
//根据Boost软件许可证1.0版发布。(参见随附的
//文件LICENSE_1_0.txt或复制到http://www.boost.org/LICENSE_1_0.txt)
//
#包括
#包括
#包括
#包括
#包括
#包括
枚举{max_length=1024};
名称空间ssl=boost::asio::ssl;
使用tcp=boost::asio::ip::tcp;
类客户端
{
使用stream=ssl::stream;
公众:
客户机(boost::asio::io_上下文和io_上下文,ssl::上下文和上下文,tcp::解析器::查询)
:context_(context)、socket_(boost::in_place_init、io_context、context_)、query_(query)、timer_(io_context)
{
套接字->设置验证模式(ssl::验证对等);
套接字->设置\验证\回调(
boost::bind(&client::verify_证书,this,_1,_2));
启动连接();
}
无效开始连接(){
解析程序(socket->get_io_context());
boost::asio::async_connect(socket_uu->lower_layer(),r.resolve(query_u),
boost::bind(&client::handle_connect),这,
boost::asio::占位符::错误);
}
void do_重新连接(){
自动&io_context=socket_uu->get_io_context();
{
boost::system::error_code ec;
插座->关闭(ec);

if(ec)std::cout查看您的实际代码会有所帮助。关于您的第二个编译错误:
*socket\uu。lower\u layer()
应该是
(*socket\uu)。lower\u layer()-很明显,你没有正确地这样做。你为什么要使用指针?这是一个X/Y问题。谢谢你的关注。很遗憾,我错过了一个
socket
而没有更改为
*socket
@sehe:请阅读[此]()。一旦你关闭了套接字,就不能再重新打开它:(@Patton即使是这个答案也承认不需要原始指针。首先,感谢您提供的详细答案。这对我来说意义重大。但您使用的是哪个版本的boost?我使用的是1.56和
boost::asio::ssl::stream socket;
没有方法
get\io\u context()
请参阅。在旧版本中,将
io_上下文
全局替换为
io_服务
您好,我在呼叫
boost::system::error\u code ec;socket\uu->shutdown(ec);if(ec)std::cout如何关闭客户端中的Ssl停止服务器或任何其他客户端?我的意思是套接字仍然处于活动状态(可以读写消息)。我只是做了一个变通:当从上层接收命令时停止处理消息,而不是真正关闭套接字
boost::asio::async_connect(*socket_.lowest_layer(), mEndpointIterator, boost::bind(&SSLHandler::handle_connect, this, boost::asio::placeholders::error));
error: request for member 'lowest_layer' in '((SSLHandler*)this)->SSLHandler::socket_', which is of pointer type 'boost::asio::ssl::stream<boost::asio::basic_stream_socket<boost::asio::ip::tcp> >*' (maybe you meant to use '->' ?)
     boost::asio::async_connect(*socket_.lowest_layer(), mEndpointIterator, boost::bind(&SSLHandler::handle_connect, this, boost::asio::placeholders::error));`
//
// client.cpp
// ~~~~~~~~~~
//
// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//

#include <cstdlib>
#include <iostream>
#include <boost/bind.hpp>
#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp>

enum { max_length = 1024 };

class client
{
public:
  client(boost::asio::io_context& io_context,
      boost::asio::ssl::context& context,
      boost::asio::ip::tcp::resolver::query query)
    : socket_(io_context, context), query_(query), timer_(io_context)
  {
    socket_.set_verify_mode(boost::asio::ssl::verify_peer);
    socket_.set_verify_callback(
        boost::bind(&client::verify_certificate, this, _1, _2));

    start_connect();
  }

  void start_connect() {
    boost::asio::ip::tcp::resolver r(socket_.get_io_context());

    boost::asio::async_connect(socket_.lowest_layer(), r.resolve(query_),
        boost::bind(&client::handle_connect, this,
          boost::asio::placeholders::error));
  }

  void do_reconnect() {
    timer_.expires_from_now(boost::posix_time::millisec(500));
    timer_.async_wait(boost::bind(&client::handle_reconnect_timer, this, boost::asio::placeholders::error));
  }

  void handle_reconnect_timer(boost::system::error_code ec) {
    if (!ec) {
      start_connect();
    }
  }

  bool verify_certificate(bool preverified,
      boost::asio::ssl::verify_context& ctx)
  {
    // The verify callback can be used to check whether the certificate that is
    // being presented is valid for the peer. For example, RFC 2818 describes
    // the steps involved in doing this for HTTPS. Consult the OpenSSL
    // documentation for more details. Note that the callback is called once
    // for each certificate in the certificate chain, starting from the root
    // certificate authority.

    // In this example we will simply print the certificate's subject name.
    char subject_name[256];
    X509* cert = X509_STORE_CTX_get_current_cert(ctx.native_handle());
    X509_NAME_oneline(X509_get_subject_name(cert), subject_name, 256);
    std::cout << "Verifying " << subject_name << "\n";

    return preverified;
  }

  void handle_connect(const boost::system::error_code& error)
  {
    if (!error)
    {
      socket_.async_handshake(boost::asio::ssl::stream_base::client,
          boost::bind(&client::handle_handshake, this,
            boost::asio::placeholders::error));
    }
    else
    {
      std::cout << "Connect failed: " << error.message() << "\n";
      do_reconnect();
    }
  }

  void accept_message() {
      std::cout << "Enter message: ";
      std::cin.getline(request_, max_length);
      size_t request_length = strlen(request_);

      boost::asio::async_write(socket_,
          boost::asio::buffer(request_, request_length),
          boost::bind(&client::handle_write, this,
            boost::asio::placeholders::error,
            boost::asio::placeholders::bytes_transferred));
    }

  void handle_handshake(const boost::system::error_code& error)
  {
    if (!error)
    {
      accept_message();
    }
    else
    {
      std::cout << "Handshake failed: " << error.message() << "\n";
      do_reconnect();
    }
  }

  void handle_write(const boost::system::error_code& error,
      size_t bytes_transferred)
  {
    if (!error)
    {
      boost::asio::async_read(socket_,
          boost::asio::buffer(reply_, bytes_transferred),
          boost::bind(&client::handle_read, this,
            boost::asio::placeholders::error,
            boost::asio::placeholders::bytes_transferred));
    }
    else
    {
      std::cout << "Write failed: " << error.message() << "\n";
      do_reconnect();
    }
  }

  void handle_read(const boost::system::error_code& error,
      size_t bytes_transferred)
  {
    if (!error)
    {
      std::cout << "Reply: ";
      std::cout.write(reply_, bytes_transferred);
      std::cout << "\n";

      accept_message(); // continue using the same socket_ until fail
    }
    else
    {
      std::cout << "Read failed: " << error.message() << "\n";
      do_reconnect();
    }
  }

private:
  boost::asio::ssl::stream<boost::asio::ip::tcp::socket> socket_;
  boost::asio::ip::tcp::resolver::query query_;
  boost::asio::deadline_timer timer_;
  char request_[max_length];
  char reply_[max_length];
};

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

    boost::asio::io_context io_context;
    boost::asio::ssl::context ctx(boost::asio::ssl::context::sslv23);
    ctx.load_verify_file("ca.pem");

        client c(io_context, ctx, {argv[1], argv[2]});

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

  return 0;
}
boost::system::error_code ec;
socket_.shutdown(ec);
if (ec) std::cout << "shutdown error: " << ec.message() << std::endl;
auto& ll = socket_.lowest_layer();

if (ll.is_open())
{
  ll.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec);
  //if (ec) std::cout << "socket.shutdown error: " << ec.message() << std::endl;

  ll.close(ec);
  //if (ec) std::cout << "socket.close error: " << ec.message() << std::endl;
}
boost::optional<stream> socket_;
void do_reconnect() {
  auto& io_context = socket_->get_io_context();
  {
      boost::system::error_code ec;
      socket_->shutdown(ec);
      if (ec) std::cout << "shutdown error: " << ec.message() << std::endl;
  }

  socket_.emplace(io_context, context_);

  timer_.expires_from_now(boost::posix_time::millisec(500));
  timer_.async_wait(boost::bind(&client::handle_reconnect_timer, this, boost::asio::placeholders::error));
}
//
// client.cpp
// ~~~~~~~~~~
//
// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//

#include <cstdlib>
#include <iostream>
#include <boost/optional.hpp>
#include <boost/bind.hpp>
#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp>

enum { max_length = 1024 };

namespace ssl = boost::asio::ssl;
using tcp = boost::asio::ip::tcp;

class client
{
    using stream = ssl::stream<tcp::socket>;
public:
  client(boost::asio::io_context& io_context, ssl::context& context, tcp::resolver::query query)
    : context_(context), socket_(boost::in_place_init, io_context, context_), query_(query), timer_(io_context)
  {
    socket_->set_verify_mode(ssl::verify_peer);
    socket_->set_verify_callback(
        boost::bind(&client::verify_certificate, this, _1, _2));

    start_connect();
  }

  void start_connect() {
    tcp::resolver r(socket_->get_io_context());

    boost::asio::async_connect(socket_->lowest_layer(), r.resolve(query_),
        boost::bind(&client::handle_connect, this,
          boost::asio::placeholders::error));
  }

  void do_reconnect() {
    auto& io_context = socket_->get_io_context();
    {
        boost::system::error_code ec;
        socket_->shutdown(ec);
        if (ec) std::cout << "shutdown error: " << ec.message() << std::endl;
    }

    socket_.emplace(io_context, context_);

    timer_.expires_from_now(boost::posix_time::millisec(500));
    timer_.async_wait(boost::bind(&client::handle_reconnect_timer, this, boost::asio::placeholders::error));
  }

  void handle_reconnect_timer(boost::system::error_code ec) {
    if (!ec) {
      start_connect();
    }
  }

  bool verify_certificate(bool preverified,
      ssl::verify_context& ctx)
  {
    // The verify callback can be used to check whether the certificate that is
    // being presented is valid for the peer. For example, RFC 2818 describes
    // the steps involved in doing this for HTTPS. Consult the OpenSSL
    // documentation for more details. Note that the callback is called once
    // for each certificate in the certificate chain, starting from the root
    // certificate authority.

    // In this example we will simply print the certificate's subject name.
    char subject_name[256];
    X509* cert = X509_STORE_CTX_get_current_cert(ctx.native_handle());
    X509_NAME_oneline(X509_get_subject_name(cert), subject_name, 256);
    std::cout << "Verifying " << subject_name << "\n";

    return preverified;
  }

  void handle_connect(const boost::system::error_code& error)
  {
    if (!error)
    {
      socket_->async_handshake(ssl::stream_base::client,
          boost::bind(&client::handle_handshake, this,
            boost::asio::placeholders::error));
    }
    else
    {
      std::cout << "Connect failed: " << error.message() << "\n";
      do_reconnect();
    }
  }

  void accept_message() {
    std::cout << "Enter message: ";
    std::cin.getline(request_, max_length);
    size_t request_length = strlen(request_);

    boost::asio::async_write(*socket_,
        boost::asio::buffer(request_, request_length),
        boost::bind(&client::handle_write, this,
          boost::asio::placeholders::error,
          boost::asio::placeholders::bytes_transferred));
  }

  void handle_handshake(const boost::system::error_code& error)
  {
    if (!error)
    {
      accept_message();
    }
    else
    {
      std::cout << "Handshake failed: " << error.message() << "\n";
      do_reconnect();
    }
  }

  void handle_write(const boost::system::error_code& error,
      size_t bytes_transferred)
  {
    if (!error)
    {
      boost::asio::async_read(*socket_,
          boost::asio::buffer(reply_, bytes_transferred),
          boost::bind(&client::handle_read, this,
            boost::asio::placeholders::error,
            boost::asio::placeholders::bytes_transferred));
    }
    else
    {
      std::cout << "Write failed: " << error.message() << "\n";
      do_reconnect();
    }
  }

  void handle_read(const boost::system::error_code& error,
      size_t bytes_transferred)
  {
    if (!error)
    {
      std::cout << "Reply: ";
      std::cout.write(reply_, bytes_transferred);
      std::cout << "\n";

      accept_message(); // continue using the same socket_ until fail
    }
    else
    {
      std::cout << "Read failed: " << error.message() << "\n";
      do_reconnect();
    }
  }

private:
  ssl::context& context_;

  boost::optional<stream> socket_;
  tcp::resolver::query query_;
  boost::asio::deadline_timer timer_;
  char request_[max_length];
  char reply_[max_length];
};

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

        boost::asio::io_context io_context;
        ssl::context ctx(ssl::context::sslv23);
        ctx.load_verify_file("ca.pem");

        client c(io_context, ctx, {argv[1], argv[2]});

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

    return 0;
}