问题
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