boost::asio ssl

以 boost::asio::ssl::stream<boost::asio::ip::tcp::socket>  代替 boost::asio::ip::tcp::socket

客户端connect成功之后, 需要socket().async_handshake(); 成功之后才能发起异步读写。

服务端accept成功之后, 需要socket().async_handshake(); 成功之后才能发起异步读写。

g++ -o server server.cpp -lboost_system-mt -lboost_filesystem-mt -lpthread -lssl

g++ -o client client.cpp -lboost_system-mt -lboost_filesystem-mt -lpthread -lssl


简单的echo server

./server 9999

./client 0.0.0.0 9999 发送消息后服务端将发回。


与tcp socket相比, 多一个handshake过程。 

数据的封包与解析与tcp完全一致。 屏蔽了ssl协议的数据。


client.cpp && server.cpp  from doc/html/boost_asio/example/ssl   boost自带的例子

server.pem && ca.pem && dh512.pem from https://github.com/microcai/netserver/tree/master/netserver


#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_service& io_service,  
      boost::asio::ssl::context& context,  
      boost::asio::ip::tcp::resolver::iterator endpoint_iterator)  
    : socket_(io_service, context)  
  {  
    socket_.set_verify_mode(boost::asio::ssl::verify_peer);  
    socket_.set_verify_callback(  
        boost::bind(&client::verify_certificate, this, _1, _2));  
  
    boost::asio::async_connect(socket_.lowest_layer(), endpoint_iterator,  
        boost::bind(&client::handle_connect, this,  
          boost::asio::placeholders::error));  
  }  
  
  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";  
    }  
  }  
  
  void handle_handshake(const boost::system::error_code& error)  
  {  
    if (!error)  
    {  
      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));  
    }  
    else  
    {  
      std::cout << "Handshake failed: " << error.message() << "\n";  
    }  
  }  
  
  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";  
    }  
  }  
  
  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";  
    }  
    else  
    {  
      std::cout << "Read failed: " << error.message() << "\n";  
    }  
  }  
  
private:  
  boost::asio::ssl::stream<boost::asio::ip::tcp::socket> socket_;  
  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_service io_service;  
  
    boost::asio::ip::tcp::resolver resolver(io_service);  
    boost::asio::ip::tcp::resolver::query query(argv[1], argv[2]);  
    boost::asio::ip::tcp::resolver::iterator iterator = resolver.resolve(query);  
  
    boost::asio::ssl::context ctx(boost::asio::ssl::context::sslv23);  
    ctx.load_verify_file("ca.pem");  
  
    client c(io_service, ctx, iterator);  
  
    io_service.run();  
   }  
  catch (std::exception& e)  
  {  
    std::cerr << "Exception: " << e.what() << "\n";  
  }  
  
  return 0;  
}  

server.cpp

#include <cstdlib>  
#include <iostream>  
#include <string>  
#include <boost/bind.hpp>  
#include <boost/asio.hpp>  
#include <boost/asio/ssl.hpp>  
  
typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> ssl_socket;  
  
class session  
{  
public:  
  session(boost::asio::io_service& io_service,  
      boost::asio::ssl::context& context)  
    : socket_(io_service, context)  
  {  
  }  
  
  ssl_socket::lowest_layer_type& socket()  
  {  
    return socket_.lowest_layer();  
  }  
  
  void start()  
  {  
    socket_.async_handshake(boost::asio::ssl::stream_base::server,  
        boost::bind(&session::handle_handshake, this,  
          boost::asio::placeholders::error));  
  }  
  
  void handle_handshake(const boost::system::error_code& error)  
  {  
    if (!error)  
    {  
      socket_.async_read_some(boost::asio::buffer(data_, max_length),  
          boost::bind(&session::handle_read, this,  
            boost::asio::placeholders::error,  
            boost::asio::placeholders::bytes_transferred));  
    }  
    else  
    {  
      delete this;  
    }  
  }  
  
  void handle_read(const boost::system::error_code& error,  
      size_t bytes_transferred)  
  {  
     if (!error)  
    {  
        std::cout <<"read: " << std::string(data_, bytes_transferred) << std::endl;  
      boost::asio::async_write(socket_,  
          boost::asio::buffer(data_, bytes_transferred),  
          boost::bind(&session::handle_write, this,  
            boost::asio::placeholders::error));  
    }  
    else  
    {  
      delete this;  
    }  
  }  
  
  void handle_write(const boost::system::error_code& error)  
  {  
    if (!error)  
    {  
      socket_.async_read_some(boost::asio::buffer(data_, max_length),  
          boost::bind(&session::handle_read, this,  
            boost::asio::placeholders::error,  
            boost::asio::placeholders::bytes_transferred));  
    }  
    else  
    {  
      delete this;  
    }  
  }  
  
private:  
  ssl_socket socket_;  
  enum { max_length = 1024 };  
  char data_[max_length];  
};  
  
class server  
{  
public:  
  server(boost::asio::io_service& io_service, unsigned short port)  
    : io_service_(io_service),  
      acceptor_(io_service,  
          boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port)),  
      context_(boost::asio::ssl::context::sslv23)  
  {  
    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("server.pem");  
    context_.use_private_key_file("server.pem", boost::asio::ssl::context::pem);  
    context_.use_tmp_dh_file("dh512.pem");  
  
    start_accept();  
  }  
  
  std::string get_password() const  
  {  
    return "test";  
  }  
  
  void start_accept()  
  {  
    session* new_session = new session(io_service_, context_);  
    acceptor_.async_accept(new_session->socket(),  
        boost::bind(&server::handle_accept, this, new_session,  
          boost::asio::placeholders::error));  
  }  
  
  void handle_accept(session* new_session,  
      const boost::system::error_code& error)  
  {  
    if (!error)  
    {  
      new_session->start();  
    }  
    else  
    {  
      delete new_session;  
    }  
  
    start_accept();  
  }  
  
private:  
  boost::asio::io_service& io_service_;  
  boost::asio::ip::tcp::acceptor acceptor_;  
  boost::asio::ssl::context context_;  
};  
  
int main(int argc, char* argv[])  
{  
  try  
  {  
    if (argc != 2)  
    {  
      std::cerr << "Usage: server <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;  
}  

猜你喜欢

转载自blog.csdn.net/i7thtool/article/details/80790810