使用Boost:ASIO和ASIO SSL示例代码通过TLS发送数据

时间:2016-02-02 18:17:56

标签: c++ boost boost-asio

目前我正在考虑使用Boost ASIO发送数据。我理解io_service是底层操作系统依赖IO功能的抽象,run()调用将轮询asio队列中的所有未完成句柄并在之后完成。

但是看看asio的SSL示例(参见下面的代码)我不知道如何设置保持连接(或会话,或其他)打开,并通过此连接读取和写入数据客户的“工作流程”。

这意味着:如果我在send()中调用客户端的handle_handshake方法,则会发送消息。但是,如果我尝试从我的主方法中调用c.send(),则Client Handshake success之后不会发生任何事情。

为什么send()在描述的场景中处理不同? io_service已经完成了吗?

注意:请不要吓唬下面的代码数量。它是随ASIO独立提供的示例代码。我只在客户端添加了一个自定义send()方法,并在一个运行示例中添加了一个执行客户端和服务器的主。

修改 我也尝试使用asio::io_service::work work(io_service);,但客户端在握手后仍然没有做任何事情。

class session{
public:
    session(asio::io_service& io_service,
            asio::ssl::context& context)
        : socket_(io_service, context)  { }

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

    void start(){
        std::cout << " Session start "<< "\n";
        socket_.async_handshake(asio::ssl::stream_base::server,
                                std::bind(&session::handle_handshake, this,
                                          std::placeholders::_1));
    }

    void handle_handshake(const asio::error_code& error){
        if (!error){
            std::cout << " Session handshake success "<< "\n";
            socket_.async_read_some(asio::buffer(data_, max_length),
                                    std::bind(&session::handle_read, this,
                                              std::placeholders::_1, std::placeholders::_2));
        }
        else {
            std::cout << " Session handshake failed "<< "\n";
            delete this;
        }
    }

    void handle_read(const asio::error_code& error,
                     size_t bytes_transferred) {
        if (!error) {
            std::cout << " Session Read success "<< "\n";
            asio::async_write(socket_,
                              asio::buffer(data_, bytes_transferred),
                              std::bind(&session::handle_write, this,
                                        std::placeholders::_1));
        }
        else {
            std::cout << " Session Read failed "<< "\n";
            delete this;
        }
    }

    void handle_write(const asio::error_code& error){
        if (!error){
            std::cout << " Write success "<< "\n";
            socket_.async_read_some(asio::buffer(data_, max_length),
                                    std::bind(&session::handle_read, this,
                                              std::placeholders::_1,
                                              std::placeholders::_2));
        }
        else{
            delete this;
        }
    }

private:
    ssl_socket socket_;
    enum { max_length = 1024 };
    char data_[max_length];
};

class server
{
public:
    server(asio::io_service& io_service, unsigned short port)
        : io_service_(io_service),
          acceptor_(io_service,
                    asio::ip::tcp::endpoint(asio::ip::tcp::v4(), port)),
          context_(asio::ssl::context::sslv23) {
        context_.set_options(
                    asio::ssl::context::default_workarounds
                    | asio::ssl::context::no_sslv2
                    | asio::ssl::context::single_dh_use);
        context_.set_password_callback(std::bind(&server::get_password, this));
        context_.use_certificate_chain_file("server.pem");
        context_.use_private_key_file("server.pem", asio::ssl::context::pem);
        context_.use_tmp_dh_file("dh1024.pem");

        start_accept();
    }

    std::string get_password() const{
        return "test";
    }

    void start_accept(){
        std::cout << " Server accept start "<< "\n";
        session* new_session = new session(io_service_, context_);
        acceptor_.async_accept(new_session->socket(),
                               std::bind(&server::handle_accept, this, new_session,
                                         std::placeholders::_1));
    }

    void handle_accept(session* new_session,
                       const asio::error_code& error){
        if (!error){
            std::cout << " Server Accept success "<< "\n";
            new_session->start();
        }
        else
        {
            delete new_session;
        }

        start_accept();
    }

private:
    asio::io_service& io_service_;
    asio::ip::tcp::acceptor acceptor_;
    asio::ssl::context context_;
};


enum { max_length = 1024 };

class client
{
public:
    client(asio::io_service& io_service,
           asio::ssl::context& context,
           asio::ip::tcp::resolver::iterator endpoint_iterator)
        : socket_(io_service, context) {
        socket_.set_verify_mode(asio::ssl::verify_peer);
        socket_.set_verify_callback(
                    std::bind(&client::verify_certificate, this, std::placeholders::_1, std::placeholders::_2));

        asio::async_connect(socket_.lowest_layer(), endpoint_iterator,
                            std::bind(&client::handle_connect, this,
                                      std::placeholders::_1));
    }

    bool verify_certificate(bool preverified,
                            asio::ssl::verify_context& ctx){
        return true;
    }

    void handle_connect(const asio::error_code& error){

        if (!error){
            std::cout << "Client Connect success "<< "\n";
            socket_.async_handshake(asio::ssl::stream_base::client,
                                    std::bind(&client::handle_handshake, this,
                                              std::placeholders::_1));
        }
        else {
            std::cout << "Client Connect failed: " << error.message() << "\n";
        }
    }

    void handle_handshake(const asio::error_code& error){
        if (!error) {
            std::cout << "Client Handshake success "<< "\n";
            //send("test") no send here
        }
        else{
            std::cout << "Client Handshake failed: " << error.message() << "\n";
        }
    }


    void send(char * request_){
        std::cout << " Client Sende daten "<< "\n";
        size_t request_length = strlen(request_);

        asio::async_write(socket_,
                          asio::buffer(request_, request_length),
                          std::bind(&client::handle_write, this,
                                    std::placeholders::_1,
                                    std::placeholders::_2));
    }

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

    void handle_read(const asio::error_code& error,  size_t bytes_transferred) {
        if (!error)  {
            std::cout << "Client Reply: ";
            std::cout.write(reply_, bytes_transferred);
            std::cout << "\n";
        }
        else {
            std::cout << "Client Read failed: " << error.message() << "\n";
        }
    }

private:
    asio::ssl::stream<asio::ip::tcp::socket> socket_;
    char request_[max_length];
    char reply_[max_length];
};

using namespace std;

int main(){

    std::thread t {
        [](){
            asio::io_service server_service;
            server s(server_service, 8877);
            server_service.run();
        }
    };

    std::this_thread::sleep_for(std::chrono::milliseconds(3000));
    asio::io_service io_service;

    asio::ip::tcp::resolver resolver(io_service);
    asio::ip::tcp::resolver::query query("127.0.0.1", std::to_string(8877));
    asio::ip::tcp::resolver::iterator iterator = resolver.resolve(query);

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

    client c(io_service, ctx, iterator);
    c.send("test");
    io_service.run();

    t.join();

    return 0;
}

0 个答案:

没有答案