Howto reconnect to a server which does not answer to close()

老子叫甜甜 提交于 2019-12-08 04:31:25

问题


I am using the C++ REST SDK ("Casablanca") to receive feed from websocket servers.

Sometimes, I need to close the connection and reconnect. The library does not have a reconnect function, so I close the old connection and simply open a new one. The problem is that the server on the other side does, as it seems, not answer to my close message.

This is the code:

web::websockets::client::websocket_callback_client*  m_clClient;

///...

void Connection::reconnect()
{
    std::cout << "Debug 1" << std::endl;
    this->m_clClient.close().get();
    delete this->m_clClient;
    this->m_clClient = new web::websockets::client::websocket_callback_client();
    std::cout << "Debug2" << std::endl;
}

As I said, it seems like the server does not answer to close(), so the program gets stuck at this->m_clClient.close().get(); forever.

I also tried deleting the session without sending a close(), like so:

web::websockets::client::websocket_callback_client*  m_clClient;

///...

void Connection::reconnect()
{
    std::cout << "Debug 1" << std::endl;
    delete this->m_clClient;
    this->m_clClient = new web::websockets::client::websocket_callback_client();
    std::cout << "Debug2" << std::endl;
}

But the program still gets stuck after "Debug 1". I think the close() is called in the destructor of websocket_callback_client if it hasn't been done before.

I have searched the source code of the library and found the destructor of websocket_callback_client here: link :

    ~wspp_callback_client()
    {
        _ASSERTE(m_state < DESTROYED);
        std::unique_lock<std::mutex> lock(m_wspp_client_lock);

        // Now, what states could we be in?
        switch (m_state) {
        case DESTROYED:
            // This should be impossible
            std::abort();
        case CREATED:
            lock.unlock();
            break;
        case CLOSED:
        case CONNECTING:
        case CONNECTED:
        case CLOSING:
            // Unlock the mutex so connect/close can use it.
            lock.unlock();
            try
            {
                // This will do nothing in the already-connected case
                pplx::task<void>(m_connect_tce).get();
            }
            catch (...) {}
            try
            {
                // This will do nothing in the already-closing case
                close().wait();
            }
            catch (...) {}
            break;
        }

        // At this point, there should be no more references to me.
        m_state = DESTROYED;
}

As you can see under case CLOSING: it waits for the connection to close.

The only possibility I can see at this point is to call close() without waiting for the answer and then overwriting the pointer with a new client, leaving the old one undeleted. This would be a very unclean solution.

What can I do to close the session and open a new one?


回答1:


The only possibility I can see at this point is to call close() without waiting for the answer and then overwriting the pointer with a new client, leaving the old one undeleted. This would be a very unclean solution.

Some cleanup could be possible using a close handler:

#include <functional>
#include <unordered_set>

#include <cpprest/ws_client.h>

using namespace std::placeholders;
using namespace web::websockets::client;

typedef std::unordered_set<websocket_callback_client *> client_list;

class Connection 
{
public:
   Connection() : clients() { 
      create_client();
   }

   void reconnect() { 
      create_client(); 
      // connect
   }

   void close_handler(websocket_callback_client * client,
              websocket_close_status status, 
              const utility::string_t & reason, 
              const std::error_code & ec) {
    // check status and/or ec first?
    clients.erase(client);
    delete client;

    // perform automatic reconnect if some flag tells so?
   }
protected:
   void create_client() {
      client = new websocket_callback_client();
      clients.insert(client);
      client->set_close_handler(std::bind(&Connection::close_handler, this,
                                          client, _1, _2, _3));
   }

   websocket_callback_client * client;
   client_list clients;
};

Since the code posted in the question is not a complete program I could not test my solution except for that it compiles (clang++ / g++).




回答2:


I ran into this issue as well and the reason I had the issue was due to my attempt to clean up the websocket_callback_client from the close handler. if I don't do that it seems to clean itself up marvelously.



来源:https://stackoverflow.com/questions/38556545/howto-reconnect-to-a-server-which-does-not-answer-to-close

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!