Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

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.


  • Lifetime Qt Champion

    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) but wsChat->disconnect(this) since you for sure won't disconnect all (also internal) signals wsChat is emitting.



  • @Christian-Ehrlicher:

    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.

    @Christian-Ehrlicher:

    Also don't use disconnect(wsChat) but wsChat->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



  • @nagesh

    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.


Log in to reply