Solved QWebSocket::textMessageReceived() emitted after the socked is disconnected
-
Hello.
I am connecting to a chat server through web sockets. Everything is nice, but when I close the connection, the QWebSocket signals keep arriving for some while, even if I forcefully delete the object.
Why is this happening and how should I "cut" the communication instead?
This is the class definition:
class Chatbot:public QObject { Q_OBJECT public: Chatbot(); ~Chatbot(); bool enterChat(); void leaveChat(); private: QString sChatURL; QWebSocket *wsChat; CBChatStatus cbcsStatus; private slots: void on_connected(); void on_disconnected(); void on_textMessageReceived(QString); signals: void logEvent(QString); };
And these are the methods, simplified for the sample:
bool Chatbot::enterChat() { bool bEC=false; if(cbcsStatus==CBChatStatus::CBCS_DISCONNECTED) { emit logEvent(QStringLiteral("Connecting...")); wsChat=new QWebSocket; QObject::connect(wsChat,SIGNAL(connected()),this,SLOT(on_connected())); QObject::connect(wsChat,SIGNAL(disconnected()),this,SLOT(on_disconnected())); QObject::connect(wsChat,SIGNAL(textMessageReceived(QString)),this,SLOT(on_textMessageReceived(QString))); cbcsStatus=CBChatStatus::CBCS_CONNECTING; // EDIT wsChat->open(QUrl(sChatURL)); bEC=true; } return bEC; } void Chatbot::leaveChat() { if(cbcsStatus!=CBChatStatus::CBCS_DISCONNECTED) { wsChat->close(); wsChat->disconnect(); // EDIT delete wsChat; wsChat=nullptr; } } void Chatbot::on_connected() { emit logEvent(QStringLiteral("** Connected **")); cbcsStatus=CBChatStatus::CBCS_CONNECTED; } void Chatbot::on_disconnected() { emit logEvent(QStringLiteral("** Disconnected **")); cbcsStatus=CBChatStatus::CBCS_DISCONNECTED; } void Chatbot::on_textMessageReceived(QString sMessage) { emit logEvent(QStringLiteral("Message received: %1").arg(sMessage)); // ... }
*The logEvent() signal is just my way of registering events.
So, after hitting some "End chat" button, which calls leaveChat(), I get the following in my log:
** Disconnected ** Message received: <some server response> Message received: <some server response> Message received: <some server response> ...
It seems that after some seconds, the server detects the connection is idle and finally closes it itself, but I should not be getting those messages in first place!
Does anybody have an idea about what's happening?
Thanks.
-
I would guess there is a second socket around otherwise I don't see why you would get the disconnected() debug output at all since you already disconnected the signals/slots. Simply inrt out the pointer of wsChat / sender() in the approriate functions.
Also don't use
disconnect(wsChat)
butwsChat->disconnect(this)
since you for sure won't disconnect all (also internal) signals wsChat is emitting. -
I would guess there is a second socket around otherwise I don't see why you would get the disconnected() debug output at all since you already disconnected the signals/slots. Simply inrt out the pointer of wsChat / sender() in the approriate functions.
I only use a single QWebSocket.
And I close it right before QObject::disconnect().
I have no idea if this close() method is synchronous, but it should be or if not, why is disconnected() being fired?I've logged wsChat in on_textMessageReceived() and it shows 0x0 !!
And when the server finally closes the connection itself, on_disconnected() is triggered again, showing that wsChat is 0x0 as well.
Just for testing, I've removed the wsChat=nullptr line inside leaveChat() (because it's worth nothing), and after that the debug line in on_textMessageReceived() crashes because wsChat is -1.
That's insane.
Also don't use
disconnect(wsChat)
butwsChat->disconnect(this)
since you for sure won't disconnect all (also internal) signals wsChat is emitting.Nothing else should fire my custom slot on_textMessageReceived() after disconnecting it.
But I used wsChat->disconnect(this), and the result is the same.
-
@Alvein Just a suggestion
In leaveChat() function call disconnectFromHost() which will trigger disconnected signal,
In on_disconnected() slot perform cleanup task -
There's no such thing as disconnectFromHost() in QWebSocket.
Previously, I tried abort(), but the resulting behavior is the same.
Deleting wsChat in on_disconnected() raises an exception in on_textMessageReceived(), because the textMessageReceived() signal keeps being triggered.
...
At this point I don't care if the socket remains open forever. I just want to remove the wsChat object signal/slot connections inside leaveChat() or on_disconnected(). Seems like an impossible task, though.
...
EDIT:
Found the problem. The posted snippet was basically good. It's hard to tell in a few words but the CALLER was not having into account that cbcsStatus can take a little while going from CBChatStatus::CBCS_DISCONNECTED to CBChatStatus::CBCS_CONNECTED.
A Chatbot instance is intended to be created multiple times, and the routine which does this decides if it's OK to invoke enterChat() according to the given instance status (CBCS_DISCONNECTED or not).
So, enterChat() was being executed twice, even if a single bot was being used, overwriting the previous wsChat value. Boom.
Solution? Just setting a new status, CBCS_CONNECTING, right before wsChat->open().
Also, once wsChat is freed, there's no need of disconnecting signals/slots, BUT:
I was wrong.
This fails
QObject::disconnect(wsChat);
This works:
wsChat->disconnect(this); // or QObject::disconnect(wsChat,nullptr,this,nullptr);
This also works (a little more general:
wsChat->disconnect(); // or QObject::disconnect(wsChat,nullptr,nullptr,nullptr);
I've done the modifications in the original snippet.
Thanks to everyone for giving me ideas.