Как переподключиться к серверу, который не отвечает закрыть ()

Я использую C++ REST SDK ("Касабланка") для получения фида с серверов веб-сокетов.

Иногда мне нужно закрыть соединение и переподключиться. В библиотеке нет reconnect функция, поэтому я закрываю старое соединение и просто открываю новое. Проблема в том, что сервер на другой стороне, как кажется, не отвечает на мое закрытое сообщение.

Это код:

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;
}

Как я уже сказал, кажется, что сервер не отвечает на close()так что программа застревает на this->m_clClient.close().get(); навсегда.

Я также попытался удалить сеанс без отправки close(), вот так:

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;
}

Но программа все еще застревает после "Отладки 1". я думаю close() называется в деструкторе websocket_callback_client если это не было сделано раньше.

Я искал исходный код библиотеки и нашел деструктор websocket_callback_client здесь: ссылка:

    ~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;
}

Как вы можете видеть под case CLOSING: он ожидает соединения, чтобы закрыть.

Единственная возможность, которую я вижу на данный момент, это позвонить close() не дожидаясь ответа, а затем перезаписывая указатель новым клиентом, оставляя старый не восстановленным. Это было бы очень нечистым решением.

Что я могу сделать, чтобы закрыть сеанс и открыть новый?

2 ответа

Я также столкнулся с этой проблемой, и причина, по которой у меня возникла проблема, была связана с моей попыткой очистить websocket_callback_client от обработчика закрытия. если я этого не сделаю, то кажется, что он изумительно очищается.

Единственная возможность, которую я вижу на данный момент, - это вызвать close(), не дожидаясь ответа, а затем перезаписав указатель новым клиентом, оставив старый не восстановленным. Это было бы очень нечистым решением.

Некоторая очистка может быть возможна с использованием обработчика закрытия:

#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;
};

Поскольку код, размещенный в вопросе, не является полной программой, я не смог протестировать свое решение, за исключением того, что оно компилируется (clang++ / g++).

Другие вопросы по тегам