【问题标题】:Get error boost asio connection timed out when try to reconnect to server尝试重新连接到服务器时获取错误提升 asio 连接超时
【发布时间】:2018-03-20 02:34:54
【问题描述】:

我需要编写一个类来处理与黑盒服务器的 ssl 连接(读/写字符数组)。我需要实现断开/连接功能。但它没有按预期工作。

用例:

  • 用户连接到服务器(工作:可以发送和接收消息)
  • 用户断开与服务器的连接,等待一段时间然后重新连接。 (失败:仅在持续时间较短时有效:例如 10 秒。如果超过此时间 handle_connect() 则返回错误 connection timed out

这是该类的源代码以及我如何使用它:

boost::asio::io_service &mioService;
SSLHandler* mpSSLConnection;

void Connector::setupConnection()
{
    try{

        std::string port = std::to_string(mPort);
        boost::asio::ip::tcp::resolver resolver(mioService);
        boost::asio::ip::tcp::resolver::query query(mHost, port);
        boost::asio::ip::tcp::resolver::iterator iterator = resolver.resolve(query);

        boost::asio::ssl::context context(boost::asio::ssl::context::sslv23);
        //    context.load_verify_file("key.pem");


        if(mpSSLConnection == nullptr)
            mpSSLConnection = new SSLHandler(mioService,context,iterator,this);





    }catch (std::exception& e){
        std::cerr << "Exception: " << e.what() << "\n";
    }
    // actually this line is called from outside the func
    mpSSLConnection->connectToServer();
}

然后像这样断开连接

void Connector::disconnect()
{
    isSetDisconnectedToSrv = true;
    mpSSLConnection->setIsDestructing(true);
    QThread::msleep(500);
    delete mpSSLConnection;
    mpSSLConnection = nullptr;
//    setupConnection();
    isConnectedToServer =false; // we did delete the object handle the ssl connection so...
    mpHandler->onServerDisconnected(); // just report to upper layer

}

最后是类源码:

#ifndef SSLHANDLER_H
#define SSLHANDLER_H
#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp>
#include <boost/bind.hpp>
#include <iostream>
#include <istream>
#include <ostream>
#include <string>
#include <queue>
#include <boost/lockfree/spsc_queue.hpp>

class Connector;
const int READ_SIZE =0;
const int READ_MSG=1;
class SSLHandler
{
public:




    SSLHandler(boost::asio::io_service& io_service, boost::asio::ssl::context& context, boost::asio::ip::tcp::resolver::iterator endpoint_iterator, Connector* pConnector)
    : socket_(io_service, context) , mEndpointIterator (endpoint_iterator) , mpConnector (pConnector),
    timer_{ io_service},
    isConnectionOk {false}
    {
        LOG_TRACE << "creating new sslhandler";
        socket_.set_verify_mode(boost::asio::ssl::context::verify_none);
        socket_.set_verify_callback(boost::bind(&SSLHandler::verify_certificate, this, _1, _2));


        mode = READ_SIZE;
    }
    ~SSLHandler();
    bool verify_certificate(bool preverified, boost::asio::ssl::verify_context& ctx);
    void handle_connect(const boost::system::error_code& error);
    void handle_handshake(const boost::system::error_code& error);
    void handle_write(const boost::system::error_code& error, size_t bytes_transferred);
    void handle_write_auth(const boost::system::error_code& error, size_t bytes_transferred);
    void handle_read_msgsize(const boost::system::error_code& error, size_t bytes_transferred);
    void handle_read_message(const boost::system::error_code& error, size_t bytes_transferred);
    void connectToServer();
    void do_reconnect();
    void handle_reconnect_timer(boost::system::error_code ec);

    void writeMessage(std::vector<char> &array);

    void setRequestMsg(std::vector<char> &&array);


    void setIsDestructing(bool value);

private:
    boost::asio::ssl::stream<boost::asio::ip::tcp::socket> socket_;
    boost::asio::ip::tcp::resolver::iterator mEndpointIterator;
    boost::asio::deadline_timer timer_;
    char reply_[0x1 << 16]; //=65356 bytes
    int mode;
    uint32_t size;
    std::vector<char> requestMsg;
    std::vector<char> replyMsg;
    Connector* mpConnector; // ptr to object compose message
    std::queue<std::vector < char> >  mQueueMsg;
    bool isConnectionOk;
    bool isDestructing =false;

private:
    void writeMessageWithQueue(std::vector<char> &array);

};

#endif // SSLHANDLER_H

#include "sslhandler.h"
#include "connector.h"
#include "BoostLogger.h"
#include <QThread>
#include "boost/enable_shared_from_this.hpp"
SSLHandler::~SSLHandler()
{
    LOG_FATAL << "ssl handler shutdown";
    if(isConnectionOk){
        socket_.lowest_layer().close();
        boost::system::error_code ec;
        socket_.shutdown(ec);
        if(ec){
            LOG_FATAL << "ssl handler socket shutdown with err: " << ec.message();
        }

        LOG_TRACE << "ssl handler shutdown complete";
    }

}

bool SSLHandler::verify_certificate(bool preverified, boost::asio::ssl::verify_context &ctx)
{
    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:\n" << subject_name << std::endl;

    return preverified;
}

void SSLHandler::handle_connect(const boost::system::error_code &error)
{
    if(isDestructing){
        LOG_TRACE << "Is destructing ssl connect so abort " ;
        return;
    }
    LOG_TRACE << "get past destructing";
    if(!error){
        isConnectionOk = true;
        LOG_TRACE << "Connection OK!" << std::endl;
        socket_.async_handshake(boost::asio::ssl::stream_base::client, boost::bind(&SSLHandler::handle_handshake, this, boost::asio::placeholders::error));
    }else{
        LOG_FATAL << "Connect failed: " << error.message() << std::endl;
        mpConnector->sendDisconnectedStatus();
        do_reconnect();
    }
}

void SSLHandler::handle_handshake(const boost::system::error_code &error)
{
    if(isDestructing){
        LOG_TRACE << "Is destructing ssl connect so abort " ;
        return;
    }
    if(!error){
        std::cout << "Sending request: " << std::endl;


        boost::asio::async_write(socket_,
           boost::asio::buffer(requestMsg.data(), requestMsg.size()),
           boost::bind(&SSLHandler::handle_write_auth, this,
               boost::asio::placeholders::error,
               boost::asio::placeholders::bytes_transferred));
    }else{
        LOG_FATAL << "Handshake failed: " << error.message() << std::endl;
        mpConnector->sendDisconnectedStatus();
        do_reconnect();
    }
}

void SSLHandler::handle_write(const boost::system::error_code &error, size_t bytes_transferred)
{
    if(isDestructing){
        LOG_TRACE << "Is destructing ssl connect so abort " ;
        return;
    }

    if (error) {
        LOG_FATAL << "Write failed: " << error.message() << std::endl;
        mpConnector->sendDisconnectedStatus();
        do_reconnect();
    }

    Q_UNUSED(bytes_transferred);
    usleep(1e4);

    if (!mQueueMsg.empty()) {
        mQueueMsg.pop();
        if(!mQueueMsg.empty()){
            auto msg = mQueueMsg.front();
            writeMessageWithQueue(msg);
        }



    }
    else{
        LOG_ERROR << "Empty queue messages!";
    }



}

void SSLHandler::handle_write_auth(const boost::system::error_code &error, size_t bytes_transferred)
{
    usleep(1e5);
    if(isDestructing){
        LOG_TRACE << "Is destructing ssl connect so abort " ;
        return;
    }

    if (!error){
        if(mode==READ_SIZE){
            mode = READ_MSG;
            std::cerr << "\nSending request read size OK!\n" << std::endl;
            //      char respond[bytes_transferred] = "";
            boost::asio::async_read(socket_, boost::asio::buffer(reply_,4),
                boost::bind(&SSLHandler::handle_read_msgsize,
                    this,
                    boost::asio::placeholders::error,
                    boost::asio::placeholders::bytes_transferred));
//            std::cerr << "respond is " ;
        }


    }else{
        LOG_FATAL << "Write failed: " << error.message() << std::endl;
        mpConnector->sendDisconnectedStatus();
        do_reconnect();
    }
}

void SSLHandler::handle_read_msgsize(const boost::system::error_code &error, size_t bytes_transferred)
{
    if(isDestructing){
        LOG_TRACE << "Is destructing ssl connect so abort " ;
        return;
    }
    if (!error){
        //first 4 bytes contain size of message
        size = getFirstFour();

        mode = READ_SIZE;
        boost::asio::async_read(socket_, boost::asio::buffer(reply_,size),
            boost::bind(&SSLHandler::handle_read_message,
                this,
//                                            mWriteId++,
                boost::asio::placeholders::error,
                boost::asio::placeholders::bytes_transferred));





    }else{
        LOG_FATAL << "Read failed: " << error.message() << std::endl;
        mpConnector->sendDisconnectedStatus();
        do_reconnect();
    }
}

void SSLHandler::handle_read_message(const boost::system::error_code &error, size_t bytes_transferred)
{
    if(isDestructing){
        LOG_TRACE << "Is destructing ssl connect so abort " ;
        return;
    }
    if (!error){


        replyMsg.clear();
        replyMsg.assign(reply_,reply_+ size);
        mpConnector->setReadMsg(replyMsg);

        mode = READ_SIZE;

        // read next message size
        boost::asio::async_read(socket_, boost::asio::buffer(reply_,4),
            boost::bind(&SSLHandler::handle_read_msgsize,
                this,
                boost::asio::placeholders::error,
                boost::asio::placeholders::bytes_transferred));

    }else{
        LOG_FATAL << "Read failed: " << error.message() << std::endl;
        mpConnector->sendDisconnectedStatus();
        do_reconnect();
    }
}

void SSLHandler::connectToServer()
{
//    boost::asio::ip::tcp::resolver r(socket_.get_io_service());
    if(isDestructing){
        LOG_TRACE << "Is destructing ssl connect so abort " ;
        return;
    }
    boost::asio::async_connect(socket_.lowest_layer(), mEndpointIterator, boost::bind(&SSLHandler::handle_connect, this, boost::asio::placeholders::error));
    LOG_TRACE << "async_connect called";
}

void SSLHandler::do_reconnect()
{
//    return;
    if(isDestructing){
        LOG_TRACE << "Is destructing ssl connect so abort " ;
        return;
    }
//    socket_.shutdown();
    isConnectionOk = false;

    else{
        socket_.lowest_layer().cancel();
        timer_.expires_from_now(boost::posix_time::millisec(500));
        timer_.async_wait(boost::bind(&SSLHandler::handle_reconnect_timer, this, boost::asio::placeholders::error()));
    }

}

void SSLHandler::handle_reconnect_timer(boost::system::error_code ec)
{
    if(!ec){
        connectToServer();
    }
    else{
        LOG_TRACE << "Error with reconnect timer : " << ec.message();
    }
}

void SSLHandler::writeMessageWithQueue(std::vector<char> &array)
{

//    std::cerr << "write : " << (void*) array.data() << " | " << array.size() << std::endl;
    if(isDestructing){
        LOG_TRACE << "Is destructing ssl connect so abort " ;
        return;
    }
    boost::asio::async_write(socket_,
       boost::asio::buffer(array.data(), array.size()),
       boost::bind(&SSLHandler::handle_write, this,
           boost::asio::placeholders::error,
           boost::asio::placeholders::bytes_transferred));
}

void SSLHandler::writeMessage(std::vector<char> &array)
{
    if(mQueueMsg.size()==0){
        mQueueMsg.push(array);
        writeMessageWithQueue(array);
    }

    else
        mQueueMsg.push(array);


}
void SSLHandler::setRequestMsg(std::vector<char> &&array)
{
    requestMsg = std::move(array);
}
void SSLHandler::setIsDestructing(bool value)
{
    LOG_INFO << "ssl connection destructing set as " << value;
    isDestructing = value;
    if(isDestructing == true){
        if(isConnectionOk){
            socket_.lowest_layer().cancel();
            //        socket_.shutdown();
            LOG_INFO << "ssl connection destructing get pass shutdown";
        }
    }
}

PS:这是奇怪的handler tracking,在(调用)disconnect() 并再次重新连接之后:没有触发任何处理程序,因此建立连接后没有握手:(

@asio|1521627714.863517|0|resolver@0x7fbe2affc898.cancel 空fz 参数!空 fz 规则!空 fz 参数!@asio____________ socket_: 0x7fbe10005150 @asio____________192.168.2.36 @asio|1521627714.864161|0*1|socket@0x7fbe10005150.async_connect @asio: 连接调用@asio|1521627714.865136|>1|ec=system:0 @asio|1521627714.865375|1*2|socket@0x7fbe10005150.async_send @asio|1521627714.865416|2|ec=system:0,bytes_transferred=517 @asio|1521627714.865429|2*3|socket@0x7fbe10005150.async_receive @asio|1521627714.865451|3|ec=system:0,bytes_transferred=994 @asio|1521627714.867764|3*4|socket@0x7fbe10005150.async_send @asio|1521627714.867792|4|ec=system:0,bytes_transferred=326 @asio|1521627714.867809|4*5|socket@0x7fbe10005150.async_receive @asio|1521627714.867817|5|ec=system:0,bytes_transferred=234 @asio|1521627714.870271|5*6|socket@0x7fbe10005150.async_send @asio|1521627714.870318|6|ec=system:0,bytes_transferred=154 @asio|1521627714.970430|6*7|socket@0x7fbe10005150.async_receive @asio|1521627714.970443|7|ec=system:0,bytes_transferred=138 @asio|1521627714.970470|7*8|socket@0x7fbe10005150.async_receive @asio|1521627714.970475|8|ec=system:0,bytes_transferred=0 @asio|1521627714.971418|8*9|socket@0x7fbe10005150.async_send @asio|1521627714.971771|8*10|deadline_timer@0x5290628.async_wait @asio|1521627714.972004|8*11|socket@0x7fbe10005150.async_receive @asio|1521627714.972012|9|ec=system:0,bytes_transferred=138 @asio|1521627714.982098|9*12|socket@0x7fbe10005150.async_send @asio|1521627714.982115|12|ec=system:0,bytes_transferred=138 @asio|1521627714.992214|12*13|socket@0x7fbe10005150.async_send @asio|1521627714.992244|11|ec=system:0,bytes_transferred=292 @asio|1521627714.992278|11*14|socket@0x7fbe10005150.async_receive @asio|1521627714.992284|13|ec=system:0,bytes_transferred=186 @asio|1521627715.002355|14|ec=system:0,bytes_transferred=0 @asio|1521627715.002469|14*15|socket@0x7fbe10005150.async_receive @asio|1521627715.002479|15|ec=system:0,bytes_transferred=0 @asio|1521627715.002495|15*16|socket@0x7fbe10005150.async_receive @asio|1521627715.002500|16|ec=system:0,bytes_transferred=0 @asio|1521627715.002550|16*17|socket@0x7fbe10005150.async_receive @asio|1521627715.002561|17|ec=system:0,bytes_transferred=154 @asio|1521627715.002581|17*18|socket@0x7fbe10005150.async_receive @asio|1521627715.002586|18|ec=system:0,bytes_transferred=0 @asio|1521627715.002636|18*19|socket@0x7fbe10005150.async_receive @asio|1521627715.002653|10|ec=system:0 @asio|1521627721.862105|10*20|socket@0x7fbe10005150.async_send @asio|1521627721.862139|10|deadline_timer@0x5290628.cancel @asio|1521627721.862144|10*21|deadline_timer@0x5290628.async_wait @asio|1521627721.862258|20|ec=system:0,bytes_transferred=138 @asio|1521627721.872365|19|ec=system:0,bytes_transferred=138 @asio|1521627721.872436|19*22|socket@0x7fbe10005150.async_receive @asio|1521627721.872443|22|ec=system:0,bytes_transferred=0 @asio|1521627721.872503|22*23|socket@0x7fbe10005150.async_receive @asio|1521627721.872515|21|ec=system:0 @asio|1521627724.862091|21*24|socket@0x7fbe10005150.async_send @asio|1521627724.862148|21|deadline_timer@0x5290628.cancel @asio|1521627724.862157|21*25|deadline_timer@0x5290628.async_wait @asio|1521627724.862272|24|ec=system:0,bytes_transferred=138 @asio|1521627724.872375|23|ec=system:0,bytes_transferred=138 @asio|1521627724.872457|23*26|socket@0x7fbe10005150.async_receive @asio|1521627724.872465|26|ec=system:0,bytes_transferred=0 @asio|1521627724.872510|26*27|socket@0x7fbe10005150.async_receive @asio|1521627724.872516|25|ec=system:0 @asio|1521627727.862084|25*28|socket@0x7fbe10005150.async_send @asio|1521627727.862120|25|deadline_timer@0x5290628.cancel @asio|1521627727.862125|25*29|deadline_timer@0x5290628.async_wait @asio|1521627727.862204|28|ec=system:0,bytes_transferred=138 @asio|1521627727.872283|27|ec=system:0,bytes_transferred=138 @asio|1521627727.872362|27*30|socket@0x7fbe10005150.async_receive @asio|1521627727.872366|30|ec=system:0,bytes_transferred=0 @asio|1521627727.872412|30*31|socket@0x7fbe10005150.async_receive @asio|1521627727.872418|29|ec=system:0 @asio|1521627730.862072|29*32|socket@0x7fbe10005150.async_send @asio|1521627730.862118|29|deadline_timer@0x5290628.cancel @asio|1521627730.862125|29*33|deadline_timer@0x5290628.async_wait @asio|1521627730.862217|32|ec=system:0,bytes_transferred=138 @asio|1521627730.872315|31|ec=system:0,bytes_transferred=138 @asio|1521627730.872406|31*34|socket@0x7fbe10005150.async_receive @asio|1521627730.872412|34|ec=system:0,bytes_transferred=0 @asio|1521627730.872458|34*35|socket@0x7fbe10005150.async_receive @asio|1521627730.872465|33|ec=system:0 @asio|1521627733.862114|33*36|socket@0x7fbe10005150.async_send @asio|1521627733.862153|33|deadline_timer@0x5290628.cancel @asio|1521627733.862158|33*37|deadline_timer@0x5290628.async_wait @asio|1521627733.862244|36|ec=system:0,bytes_transferred=138 @asio|1521627733.872342|35|ec=system:0,bytes_transferred=138 @asio|1521627733.872416|35*38|socket@0x7fbe10005150.async_receive @asio|1521627733.872422|38|ec=system:0,bytes_transferred=0 @asio|1521627733.872461|38*39|socket@0x7fbe10005150.async_receive @asio|1521627733.872466|37|ec=system:0 @asio|1521627736.862158|37*40|socket@0x7fbe10005150.async_send @asio|1521627736.862235|37|deadline_timer@0x5290628.cancel @asio|1521627736.862242|37*41|deadline_timer@0x5290628.async_wait @asio|1521627736.862406|40|ec=system:0,bytes_transferred=138 @asio|1521627736.872497|39|ec=system:0,bytes_transferred=138 @asio|1521627736.872622|39*42|socket@0x7fbe10005150.async_receive @asio|1521627736.872638|42|ec=system:0,bytes_transferred=0 @asio|1521627736.872720|42*43|socket@0x7fbe10005150.async_receive @asio|1521627736.872726|41|ec=system:0 @asio|1521627739.862096|41*44|socket@0x7fbe10005150.async_send @asio|1521627739.862144|41|deadline_timer@0x5290628.cancel @asio|1521627739.862148|41*45|deadline_timer@0x5290628.async_wait @asio|1521627739.862243|44|ec=system:0,bytes_transferred=138 @asio|1521627739.872335|43|ec=system:0,bytes_transferred=138 @asio|1521627739.872421|43*46|socket@0x7fbe10005150.async_receive @asio|1521627739.872425|46|ec=system:0,bytes_transferred=0 @asio|1521627739.872477|46*47|socket@0x7fbe10005150.async_receive @asio|1521627739.872492|45|ec=system:0 @asio|1521627742.862121|45*48|socket@0x7fbe10005150.async_send @asio|1521627742.862204|45|deadline_timer@0x5290628.cancel @asio|1521627742.862211|45*49|deadline_timer@0x5290628.async_wait @asio|1521627742.862392|48|ec=system:0,bytes_transferred=138 @asio|1521627742.872491|47|ec=system:0,bytes_transferred=138 @asio|1521627742.872592|47*50|socket@0x7fbe10005150.async_receive @asio|1521627742.872600|50|ec=system:0,bytes_transferred=0 @asio|1521627742.872675|50*51|socket@0x7fbe10005150.async_receive @asio|1521627742.872688|51|ec=system:125,bytes_transferred=0 @asio|1521627745.316858|49|ec=system:0 @asio|1521627745.861984|

【问题讨论】:

  • 你上次得到的代码怎么了?我看到sleeps、newdelete 等。这不是好的代码。
  • 另外,我不清楚问题是什么:“失败:它只在持续时间很短时才有效:比如 10 秒。” - 持续时间是多少? “如果超过那个 handle_connect() 返回错误连接超时)” - 我上一个答案中的代码would simply schedule a new connection attempt if handle_connect() received an error
  • 嗨,我的意思是用户主动调用断开功能(不是像上次那样被网络断开连接)。如果用户调用disconnect()然后等待超过10秒,然后调用connect()连接失败,错误:connection timed out
  • 您的 do_reconnect 有一个流氓“else”块。你能把代码改成你实际使用的吗?
  • 可悲的是,这是我实际使用的 :( 我只是剥离了编写要由 SSLHandler 编写的消息的类:p

标签: c++ boost boost-asio


【解决方案1】:

我将示例修复为独立的,并在演示服务器上运行它:

#include <iostream>
#include <sstream>
#include <vector>

#ifdef STANDALONE
    namespace {
        struct LogTx {
            std::stringstream _ss;
            std::ostream& _os;
            bool _armed = true;

            LogTx(std::ostream& os) : _os(os) {}
            LogTx(LogTx&& rhs) : _ss(std::move(rhs._ss)), _os(rhs._os) { rhs._armed = false; }
            ~LogTx() { if (_armed) _os << _ss.rdbuf() << std::endl; }

            LogTx operator<<(std::ostream&(&v)(std::ostream&)) { _ss << v; return std::move(*this); }
            template <typename T> LogTx operator<<(T&& v) { _ss << v; return std::move(*this); }
        };

    }

#   define LOG_FATAL LogTx(std::cerr) << "FATAL: "
#   define LOG_TRACE LogTx(std::clog) << "TRACE: "
#   define LOG_ERROR LogTx(std::cerr) << "ERROR: "
#   define LOG_INFO  LogTx(std::clog) << "INFO:  "
#   define Q_UNUSED(a) static_cast<void>(a)

    namespace {
        struct Connector {
            void sendDisconnectedStatus()               { LOG_INFO << "Disconnected"; }
            void setReadMsg(std::vector<char> const& v) { LOG_INFO << "response: '" << std::string(v.begin(), v.end()) << "'"; }
        };
    }
#endif

#ifndef SSLHANDLER_H
#define SSLHANDLER_H
#include <boost/endian/arithmetic.hpp> // for big_uint32_t
#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp>
#include <boost/bind.hpp>
#include <queue>
#include <string>
#include <thread>

const int READ_SIZE = 0;
const int READ_MSG = 1;

class SSLHandler {
  public:
    SSLHandler(boost::asio::io_service &io_service, boost::asio::ssl::context &context,
               boost::asio::ip::tcp::resolver::iterator endpoint_iterator, Connector *pConnector)
            : socket_(io_service, context), mEndpointIterator(endpoint_iterator),
              mpConnector(pConnector), timer_{ io_service }, isConnectionOk{ false } 
    {
        LOG_TRACE << "creating new sslhandler";
        socket_.set_verify_mode(boost::asio::ssl::context::verify_none);
        socket_.set_verify_callback(boost::bind(&SSLHandler::verify_certificate, this, _1, _2));

        mode = READ_SIZE;
    }
    ~SSLHandler();
    bool verify_certificate(bool preverified, boost::asio::ssl::verify_context &ctx);
    void handle_connect(const boost::system::error_code &error);
    void handle_handshake(const boost::system::error_code &error);
    void handle_write(const boost::system::error_code &error, size_t bytes_transferred);
    void handle_write_auth(const boost::system::error_code &error, size_t bytes_transferred);
    void handle_read_msgsize(const boost::system::error_code &error, size_t bytes_transferred);
    void handle_read_message(const boost::system::error_code &error, size_t bytes_transferred);
    void connectToServer();
    void do_reconnect();
    void handle_reconnect_timer(boost::system::error_code ec);

    void writeMessage(std::vector<char> &array);

    void setRequestMsg(std::vector<char> &&array);

    void setIsDestructing(bool value);

  private:
    boost::asio::ssl::stream<boost::asio::ip::tcp::socket> socket_;
    boost::asio::ip::tcp::resolver::iterator mEndpointIterator;
    Connector *mpConnector; // ptr to object compose message
    boost::asio::deadline_timer timer_;
    char reply_[0x1 << 16]; //=65356 bytes

    size_t getFirstFour() {
        return *boost::asio::buffer_cast<boost::endian::big_uint32_t *>(boost::asio::buffer(reply_));
    };

    int mode;
    uint32_t size;
    std::vector<char> requestMsg;
    std::vector<char> replyMsg;
    std::queue<std::vector<char> > mQueueMsg;
    bool isConnectionOk;
    bool isDestructing = false;

  private:
    void writeMessageWithQueue(std::vector<char> &array);
};

#endif // SSLHANDLER_H

//#include "sslhandler.h"
//#include "connector.h"
//#include "BoostLogger.h"
//#include <QThread>
//#include "boost/enable_shared_from_this.hpp"

SSLHandler::~SSLHandler() {
    LOG_FATAL << "ssl handler shutdown";
    if (isConnectionOk) {
        socket_.lowest_layer().close();
        boost::system::error_code ec;
        socket_.shutdown(ec);
        if (ec) {
            LOG_FATAL << "ssl handler socket shutdown with err: " << ec.message();
        }

        LOG_TRACE << "ssl handler shutdown complete";
    }
}

bool SSLHandler::verify_certificate(bool preverified, boost::asio::ssl::verify_context &ctx) {
    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:\n" << subject_name << std::endl;

    return preverified;
}

void SSLHandler::handle_connect(const boost::system::error_code &error) {
    if (isDestructing) {
        LOG_TRACE << "Is destructing ssl connect so abort ";
        return;
    }
    LOG_TRACE << "get past destructing";
    if (!error) {
        isConnectionOk = true;
        LOG_TRACE << "Connection OK!" << std::endl;
        socket_.async_handshake(boost::asio::ssl::stream_base::client,
                                boost::bind(&SSLHandler::handle_handshake, this, boost::asio::placeholders::error));
    } else {
        LOG_FATAL << "Connect failed: " << error.message() << std::endl;
        mpConnector->sendDisconnectedStatus();
        do_reconnect();
    }
}

void SSLHandler::handle_handshake(const boost::system::error_code &error) {
    if (isDestructing) {
        LOG_TRACE << "Is destructing ssl connect so abort ";
        return;
    }
    if (!error) {
        std::cout << "Sending request: " << std::endl;

        boost::asio::async_write(socket_, boost::asio::buffer(requestMsg.data(), requestMsg.size()),
                                 boost::bind(&SSLHandler::handle_write_auth, this, boost::asio::placeholders::error,
                                             boost::asio::placeholders::bytes_transferred));
    } else {
        LOG_FATAL << "Handshake failed: " << error.message() << std::endl;
        mpConnector->sendDisconnectedStatus();
        do_reconnect();
    }
}

void SSLHandler::handle_write(const boost::system::error_code &error, size_t bytes_transferred) {
    if (isDestructing) {
        LOG_TRACE << "Is destructing ssl connect so abort ";
        return;
    }

    if (error) {
        LOG_FATAL << "Write failed: " << error.message() << std::endl;
        mpConnector->sendDisconnectedStatus();
        do_reconnect();
    }

    Q_UNUSED(bytes_transferred);
    std::this_thread::sleep_for(std::chrono::milliseconds(10));

    if (!mQueueMsg.empty()) {
        mQueueMsg.pop();
        if (!mQueueMsg.empty()) {
            auto msg = mQueueMsg.front();
            writeMessageWithQueue(msg);
        }

    } else {
        LOG_ERROR << "Empty queue messages!";
    }
}

void SSLHandler::handle_write_auth(const boost::system::error_code &error, size_t bytes_transferred) {
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
    if (isDestructing) {
        LOG_TRACE << "Is destructing ssl connect so abort ";
        return;
    }

    if (!error) {
        if (mode == READ_SIZE) {
            mode = READ_MSG;
            std::cerr << "\nSending request read size OK!\n" << std::endl;
            //      char respond[bytes_transferred] = "";
            boost::asio::async_read(socket_, boost::asio::buffer(reply_, 4),
                                    boost::bind(&SSLHandler::handle_read_msgsize, this,
                                                boost::asio::placeholders::error,
                                                boost::asio::placeholders::bytes_transferred));
            //            std::cerr << "respond is " ;
        }

    } else {
        LOG_FATAL << "Write failed: " << error.message() << std::endl;
        mpConnector->sendDisconnectedStatus();
        do_reconnect();
    }
}

void SSLHandler::handle_read_msgsize(const boost::system::error_code &error, size_t bytes_transferred) {
    if (isDestructing) {
        LOG_TRACE << "Is destructing ssl connect so abort ";
        return;
    }
    if (!error) {
        // first 4 bytes contain size of message
        size = getFirstFour();
        LOG_TRACE << "Decoded size: " << size;

        mode = READ_SIZE;
        boost::asio::async_read(socket_, boost::asio::buffer(reply_, size),
                                boost::bind(&SSLHandler::handle_read_message, this,
                                            //                                            mWriteId++,
                                            boost::asio::placeholders::error,
                                            boost::asio::placeholders::bytes_transferred));

    } else {
        LOG_FATAL << "Read failed: " << error.message() << std::endl;
        mpConnector->sendDisconnectedStatus();
        do_reconnect();
    }
}

void SSLHandler::handle_read_message(const boost::system::error_code &error, size_t bytes_transferred) {
    if (isDestructing) {
        LOG_TRACE << "Is destructing ssl connect so abort ";
        return;
    }
    if (!error) {

        replyMsg.clear();
        replyMsg.assign(reply_, reply_ + size);
        mpConnector->setReadMsg(replyMsg);

        mode = READ_SIZE;

        // read next message size
        boost::asio::async_read(socket_, boost::asio::buffer(reply_, 4),
                                boost::bind(&SSLHandler::handle_read_msgsize, this, boost::asio::placeholders::error,
                                            boost::asio::placeholders::bytes_transferred));

    } else {
        LOG_FATAL << "Read failed: " << error.message() << std::endl;
        mpConnector->sendDisconnectedStatus();
        do_reconnect();
    }
}

void SSLHandler::connectToServer() {
    //    boost::asio::ip::tcp::resolver r(socket_.get_io_service());
    if (isDestructing) {
        LOG_TRACE << "Is destructing ssl connect so abort ";
        return;
    }
    boost::asio::async_connect(socket_.lowest_layer(), mEndpointIterator,
                               boost::bind(&SSLHandler::handle_connect, this, boost::asio::placeholders::error));
    LOG_TRACE << "async_connect called";
}

void SSLHandler::do_reconnect() {
    //    socket_.shutdown();
    isConnectionOk = false;
    //    return;
    if (isDestructing) {
        LOG_TRACE << "Is destructing ssl connect so abort ";
        return;
    } else {
        socket_.lowest_layer().cancel();
        timer_.expires_from_now(boost::posix_time::millisec(500));
        timer_.async_wait(boost::bind(&SSLHandler::handle_reconnect_timer, this, boost::asio::placeholders::error()));
    }
}

void SSLHandler::handle_reconnect_timer(boost::system::error_code ec) {
    if (!ec) {
        connectToServer();
    } else {
        LOG_TRACE << "Error with reconnect timer : " << ec.message();
    }
}

void SSLHandler::writeMessageWithQueue(std::vector<char> &array) {

    //    std::cerr << "write : " << (void*) array.data() << " | " << array.size() << std::endl;
    if (isDestructing) {
        LOG_TRACE << "Is destructing ssl connect so abort ";
        return;
    }
    boost::asio::async_write(socket_, boost::asio::buffer(array.data(), array.size()),
                             boost::bind(&SSLHandler::handle_write, this, boost::asio::placeholders::error,
                                         boost::asio::placeholders::bytes_transferred));
}

void SSLHandler::writeMessage(std::vector<char> &array) {
    if (mQueueMsg.size() == 0) {
        mQueueMsg.push(array);
        writeMessageWithQueue(array);
    }

    else
        mQueueMsg.push(array);
}
void SSLHandler::setRequestMsg(std::vector<char> &&array) { requestMsg = std::move(array); }
void SSLHandler::setIsDestructing(bool value) {
    LOG_INFO << "ssl connection destructing set as " << value;
    isDestructing = value;
    if (isDestructing == true) {
        if (isConnectionOk) {
            socket_.lowest_layer().cancel();
            //        socket_.shutdown();
            LOG_INFO << "ssl connection destructing get pass shutdown";
        }
    }
}

int main() {
    Connector c;

    boost::asio::io_service svc;
    boost::asio::ssl::context ctx(boost::asio::ssl::context_base::sslv23_client);

    SSLHandler h(svc, ctx, boost::asio::ip::tcp::resolver{svc}.resolve({{}, 6767}), &c);
    h.setRequestMsg({'h','e','l','l','o','\n','w','o','r','l','d'});
    h.connectToServer();

    svc.run();
}

现在,无论服务器在中断后恢复多长时间,我都没有发现任何问题。

你提到

嗨,我的意思是用户主动调用断开功能(不是像上次那样被网络断开连接)。如果用户调用 disconnect() 然后等待超过 10 秒,然后调用 connect() 连接失败并出现错误:连接超时。 – 巴顿11 hours ago

您的代码中没有这样的disconnect() 函数,我也看不出它是如何实现的。因此,无论是

  • 问题出在服务器端(停止接受连接或完成 SSL 握手?)
  • 问题在于您没有显示的代码

【讨论】:

  • 你可以Ctrl F这句话“和这样断开连接”看看我在上层做了什么,基本上我只是删除SSLHandler对象并创建一个新的:p
  • 啊。我错过了那部分。我认为代码是独立的,我在我的编辑器中搜索
  • @Patton 你在哪里运行io_service?难道它只是用完了工作?
  • io_service 在另一个对象中运行,我很确定它是有效的并且未被触及(我将 log 放在它的析构函数中,它总是在最后调用,在 SSLHandlerConnector 之前被摧毁)
  • 那既不是这里也不是那里。我不知道它是否改变了。我也不怀疑它是否被破坏了。我想知道它是否会在一段时间后用完。 (另外,您的意思是“ SSLHandlerConnector 被破坏之后”?请注意并尽可能准确)
猜你喜欢
  • 1970-01-01
  • 2016-01-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多