zaphoyd / websocketpp

C++ websocket client/server library
http://www.zaphoyd.com/websocketpp
Other
6.94k stars 1.96k forks source link

Disconnection Identification and Reconnection in websockets #692

Open akankshagupta29 opened 6 years ago

akankshagupta29 commented 6 years ago

How can I identify disconnection in websockets and perform reconnection ?

dontsovcmc commented 6 years ago

How can I check if connection timeout received? Should I check fail_handler or can check state of endpoint?

zaphoyd commented 6 years ago

the close and/or fail handlers should be used to check for disconnection and failed connections, including timeouts. In the close and fail handlers you can ask the connection for the error code for why it failed using connection::get_ec().

There are several different places that error codes would be listed, depending on the component that produced the error. websocketpp::error::open_handshake_timeout, websocketpp::error::close_handshake_timeout, and websocketpp::transport::asio::socket::error::tls_handshake_timeout are some of the ones I'd look for. There might be some others, all error codes are defined in namespaces that include error

dontsovcmc commented 6 years ago

I see Timer Expired in fail_handler. But, what should I do to reconnect if I hadn't got connectoin after X seconds? call "m_endpoint.connect(con);" second time or destroy everything and create connection from the begining?

dontsovcmc commented 6 years ago

I have a little syncronious loop, but need to understand Boost for working.

Can I call stop() before connect() and if something wrong?

void connect(const string uri)
{
        m_endpoint.start_perpetual();

        websocketpp::lib::error_code ec;
        con = m_endpoint.get_connection(uri, ec);
        if (ec)
            throw websocketpp::exception(ec.message());

        m_endpoint.connect(con);
        ws_thread.reset(new websocketpp::lib::thread(&websocketpp::client<config>::run, &m_endpoint));

        //here I wait  websocketpp::session::state::open for some seconds
}

void stop()
{
        close(); //close if connection state = websocketpp::session::state::open
        m_endpoint.stop_perpetual();
        if (ws_thread && ws_thread->joinable())
        {
            ws_thread->join();
        }
        ws_thread.reset();
}

I ask for this, cause I can't reconnect to server after turn off wire..
The connection state = "connection" for infinity.

dontsovcmc commented 6 years ago
SETUP
init()

MAIN_LOOP 
try
{
     if (not_connected)
             connect(url, timeout_ms))
      //do smth
      ping();
}
catch (...)
{
       close()
}

EXIT
close()
stop()

I got success reconnect with this functions,but freezed in ws_thread->join:

    void init()
    {
        m_endpoint.clear_access_channels(websocketpp::log::alevel::all);
        m_endpoint.clear_error_channels(websocketpp::log::alevel::all);
        m_endpoint.init_asio();
        m_endpoint.start_perpetual();
        ws_thread.reset(new websocketpp::lib::thread(&websocketpp::client<config>::run, &m_endpoint));
     }

    void connect(const std::string &uri_extract, const uint32_t timeout_ms)
    {
        websocketpp::lib::error_code ec;
        con.reset();   // reset connection !
        con = m_endpoint.get_connection(uri_extract, ec);
        if (ec)
            throw websocketpp::exception(ec.message());

        m_endpoint.connect(con);
        wait_connect(timeout_ms);    //loop while con->get_state() == websocketpp::session::state::open
    }

    void close() 
    {
        websocketpp::close::status::value code(websocketpp::close::status::normal);
        if (con)
        {
            if (con->get_state() == websocketpp::session::state::open)
                m_endpoint.close(con->get_handle(), code, "");
            con.reset(); //reset connection!
        }
    }

    void stop()
    {
        m_endpoint.stop_perpetual();

        if (ws_thread && ws_thread->joinable())
        {
            ws_thread->join();
        }
        ws_thread.reset();
    }
dontsovcmc commented 6 years ago

Very interesting: If I don't turn off wire, io_service.run() correct returned and join() passed, but if I do this steps:

I freezed in ws_thread->join() !

zaphoyd commented 6 years ago

if you are running your client endpoint in perpetual mode there is no need to reset the endpoint or the Asio io_service between connects. An endpoint can have multiple connections over its lifetime (including multiple outstanding at the same time). If a connection fails or disconnects and you want to reconnect, just call endpoint::connect again.

dontsovcmc commented 6 years ago

I have a class:

class X
{
        client_web_socket<config> m_endpoint;
        typename client_web_socket<config>::connection_ptr con;
};

What should I do for Reconnect?

Thanks a lot!

dontsovcmc commented 6 years ago

I return "get_connection" for reconnect:

        con = m_endpoint.get_connection(uri_extract, ec);
        if (ec)
            throw websocketpp::exception(ec.message());
        m_endpoint.connect(con);

see cpp file https://pastebin.com/PnBhHm0p & header https://pastebin.com/LELTkFde main.cpp https://pastebin.com/Pa3YR4zZ

What I see in log:

start connecting
connected
ping ok
ping ok
//BROKE WIRE
ping ok
ping ok
ping ok
ping ok
ping ok  
exception: invalid state //only after ~10 seconds i got exception
start connecting  // call get_connection & connect
exception: websocket connect timeout, state=0  //connecting
start connecting
[2018-03-01 18:04:15.948] et_fail_handler: Timer Expired
exception: websocket connect timeout, state=0
start connecting
[2018-03-01 18:04:18.970] set_fail_handler: Timer Expired
exception: websocket connect timeout, state=0
start connecting
[2018-03-01 18:04:21.986] set_fail_handler: Timer Expired
exception: websocket connect timeout, state=0
start connecting
[2018-03-01 18:04:25.001] set_fail_handler: Timer Expired
exception: websocket connect timeout, state=0
start connecting
[2018-03-01 18:04:28.026] set_fail_handler: Timer Expired
exception: websocket connect timeout, state=0
start connecting
[2018-03-01 18:04:31.061] set_fail_handler: Timer Expired
exception: websocket connect timeout, state=0
start connecting
[2018-03-01 18:04:34.078] set_fail_handler: Timer Expired
exception: websocket connect timeout, state=0
// I RETURN WIRE , wait for success
start connecting
connected      
exception: invalid state   
start connecting
connected
exception: invalid state
start connecting
connected
exception: invalid state
start connecting
connected
exception: invalid state
start connecting
connected
exception: invalid state
start connecting
connected
exception: invalid state
start connecting
connected
exception: invalid state
start connecting
connected
exception: invalid state
start connecting
connected
exception: invalid state
start connecting
connected
exception: invalid state  //WOW ! I have a lot of connections with invalid state
http://192.168.50.140/api/configuration/firmware
http://192.168.50.140/api/configuration/firmware
http://192.168.50.140/api/configuration/firmware
http://192.168.50.140/api/configuration/firmware
http://192.168.50.140/api/configuration/firmware
http://192.168.50.140/api/configuration/firmware
http://192.168.50.140/api/configuration/firmware
http://192.168.50.140/api/configuration/firmware
http://192.168.50.140/api/configuration/firmware   // why I received a lot of same "welcome" messages?

// EXIT loop, call close() & stop()

[2018-03-01 18:04:45.181] [logger] [error] [adapter] : close connection error: invalid state
[2018-03-01 18:04:48.174] [logger] [warning] [adapter] : : set_fail_handler: Timer Expired
[2018-03-01 18:04:49.178] [logger] [warning] [adapter] : : set_fail_handler: Timer Expired
//after ~200seconds I got new message:
http://192.168.50.140/api/devices/25093
http://192.168.50.140/api/devices/25093
http://192.168.50.140/api/devices/25093
http://192.168.50.140/api/devices/25093
http://192.168.50.140/api/devices/25093
http://192.168.50.140/api/devices/25093
http://192.168.50.140/api/devices/25093
http://192.168.50.140/api/devices/25093
http://192.168.50.140/api/devices/25093
//freeze in join()

I think, that I should call close() for all "demon" connections? I need only 1 connection and don't want to save handlers for all another...

What I do wrong? Thanks a lot!

vladLozkin commented 5 years ago

Hey youre cpp files are not longer avilable in the link that you provided can you upload them again please

I return "get_connection" for reconnect:

        con = m_endpoint.get_connection(uri_extract, ec);
        if (ec)
            throw websocketpp::exception(ec.message());
        m_endpoint.connect(con);

see cpp file https://pastebin.com/PnBhHm0p & header https://pastebin.com/LELTkFde main.cpp https://pastebin.com/Pa3YR4zZ

What I see in log:

start connecting
connected
ping ok
ping ok
//BROKE WIRE
ping ok
ping ok
ping ok
ping ok
ping ok  
exception: invalid state //only after ~10 seconds i got exception
start connecting  // call get_connection & connect
exception: websocket connect timeout, state=0  //connecting
start connecting
[2018-03-01 18:04:15.948] et_fail_handler: Timer Expired
exception: websocket connect timeout, state=0
start connecting
[2018-03-01 18:04:18.970] set_fail_handler: Timer Expired
exception: websocket connect timeout, state=0
start connecting
[2018-03-01 18:04:21.986] set_fail_handler: Timer Expired
exception: websocket connect timeout, state=0
start connecting
[2018-03-01 18:04:25.001] set_fail_handler: Timer Expired
exception: websocket connect timeout, state=0
start connecting
[2018-03-01 18:04:28.026] set_fail_handler: Timer Expired
exception: websocket connect timeout, state=0
start connecting
[2018-03-01 18:04:31.061] set_fail_handler: Timer Expired
exception: websocket connect timeout, state=0
start connecting
[2018-03-01 18:04:34.078] set_fail_handler: Timer Expired
exception: websocket connect timeout, state=0
// I RETURN WIRE , wait for success
start connecting
connected      
exception: invalid state   
start connecting
connected
exception: invalid state
start connecting
connected
exception: invalid state
start connecting
connected
exception: invalid state
start connecting
connected
exception: invalid state
start connecting
connected
exception: invalid state
start connecting
connected
exception: invalid state
start connecting
connected
exception: invalid state
start connecting
connected
exception: invalid state
start connecting
connected
exception: invalid state  //WOW ! I have a lot of connections with invalid state
http://192.168.50.140/api/configuration/firmware
http://192.168.50.140/api/configuration/firmware
http://192.168.50.140/api/configuration/firmware
http://192.168.50.140/api/configuration/firmware
http://192.168.50.140/api/configuration/firmware
http://192.168.50.140/api/configuration/firmware
http://192.168.50.140/api/configuration/firmware
http://192.168.50.140/api/configuration/firmware
http://192.168.50.140/api/configuration/firmware   // why I received a lot of same "welcome" messages?

// EXIT loop, call close() & stop()

[2018-03-01 18:04:45.181] [logger] [error] [adapter] : close connection error: invalid state
[2018-03-01 18:04:48.174] [logger] [warning] [adapter] : : set_fail_handler: Timer Expired
[2018-03-01 18:04:49.178] [logger] [warning] [adapter] : : set_fail_handler: Timer Expired
//after ~200seconds I got new message:
http://192.168.50.140/api/devices/25093
http://192.168.50.140/api/devices/25093
http://192.168.50.140/api/devices/25093
http://192.168.50.140/api/devices/25093
http://192.168.50.140/api/devices/25093
http://192.168.50.140/api/devices/25093
http://192.168.50.140/api/devices/25093
http://192.168.50.140/api/devices/25093
http://192.168.50.140/api/devices/25093
//freeze in join()

I think, that I should call close() for all "demon" connections? I need only 1 connection and don't want to save handlers for all another...

What I do wrong? Thanks a lot!