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

QWebSocket - Sending on disconnected socket is not an error?



  • Please consider the following code:

    void WebsocketClientQtImpl::sendText(std::string const& message)
    {
        QString messageAsQtString = QString::fromStdString(message);
        qint64 bytesSent = m_qtWebsocket->sendTextMessage(messageAsQtString);
    
        if( !bytesSent )
        {
            std::string errorMessage = m_qtWebsocket->errorString().toStdString();
            QAbstractSocket::SocketError errorCode = m_qtWebsocket->error();
        }
    }
    

    A) It seems extremely strange that a call to an asynchronous send would return the bytes sent, rather than let you know in the callback.

    B) A return of zero seems to be the only indication that a send was attempted when disconnected. If a send is attempted while disconnected, it appears that Qt issues no error or error callback. If you call error() or errorString() on the socket, it returns an empty string and UnknownError respectively.

    I can only conclude Qt doesn't consider calling send on a disconnected socket an error at all and doesn't care to notify you.

    Doesn't this behavior seem incorrect to anyone else? Did I misunderstand my debugging or come to the wrong conclusions?



  • @Fleshbits said in QWebSocket - Sending on disconnected socket is not an error?:

    if( !bytesSent )
    {

    Don't do this for non bool types...compare to a convertible scalar value such as == 0.

    I see nothing wrongwith the method returning a byteCount of zero it it is not connected, which is probably the case, and what is "!0" ?



  • @Kent-Dorfman In 14 years of C++ I've never had a problem evaluating a whether an integral value is zero or non zero using the bool operator. If it was expected to be a negative value, I could see a problem, but you can't send negative bytes. Can you explain your reasoning?

    Also, while you might not see anything wrong with it returning zero to let me know I am disconnected, can you verify that is what it is actually supposed to do?

    Might it ever return a non zero value that is smaller than the string I am trying to send? Am I supposed to loop here and send at an index?

    How would an async send know how much was sent when I post a send operation?



  • @Fleshbits said in QWebSocket - Sending on disconnected socket is not an error?:

    if( !bytesSent )

    And why don't you rely on checking the error signal instead?



  • @Pablo-J-Rogina I did indeed check the error signal. It does not fire in this case, as mentioned in the post.



  • @Fleshbits so is it an error after all?



  • @Pablo-J-Rogina said in QWebSocket - Sending on disconnected socket is not an error?:

    @Fleshbits so is it an error after all?

    I don't follow you.

    Qt will not fire an error signal, when you send on a disconnected socket, in my testing.

    If you call error() on the socket, after attempting to send on a disconnected socket, it is set to "Unknown Error", which I assume is its default initialized value when Qt doesn't think any error occurred.

    The only indication, that I can see in my testing, to let me know I tried to send on a disconnected socket, is that the send itself returns zero bytes.

    All of this is explained in the original post, no?



  • @Fleshbits my rationale is why you're considering bytesSent = 0 as an error while Qt framework is not...



  • @Pablo-J-Rogina said in QWebSocket - Sending on disconnected socket is not an error?:

    @Fleshbits my rationale is why you're considering bytesSent = 0 as an error while Qt framework is not...

    Your rationale for what?

    Are you suggesting, what Qt considers, a proper way to be notified that I tried to send on a disconnected socket? Because that is what I am after.

    If it is connecting to QWebSocket::Error

    QObject::connect(m_qtWebsocket,
                         QOverload<QAbstractSocket::SocketError>::of(&QWebSocket::error),
                         this,
                         &WebsocketClientQtImpl::onError);
    

    I'm again, saying that it does not fire in this case, in my testing.
    and I am here to find out:
    A) Why not
    B) How I am supposed to be alerted of that I just tried to send on a disconnected socket.



  • @Fleshbits said in QWebSocket - Sending on disconnected socket is not an error?:

    of that I just tried to send on a disconnected socket.

    I'd say you'll be notified when a socket disconnects by signal disconnected() and you could also check about the state() of the socket before sending any further data



  • @Pablo-J-Rogina said in QWebSocket - Sending on disconnected socket is not an error?:

    @Fleshbits said in QWebSocket - Sending on disconnected socket is not an error?:

    of that I just tried to send on a disconnected socket.

    I'd say you'll be notified when a socket disconnects by signal [disconnected()]and

    What if it was never connected in the first place?

    Sure, I can check state every time myself, but does that seem like the right thing to do? Why wouldn't Qt consider this obvious error and actual error?


  • Lifetime Qt Champion

    @Fleshbits said in QWebSocket - Sending on disconnected socket is not an error?:

    What if it was never connected in the first place?
    Sure, I can check state every time myself

    That would be your fault. And there is no need to check everytime, just make sure you connect before using.



  • @jsulm said in QWebSocket - Sending on disconnected socket is not an error?:

    @Fleshbits said in QWebSocket - Sending on disconnected socket is not an error?:

    What if it was never connected in the first place?
    Sure, I can check state every time myself

    That would be your fault. And there is no need to check every time, just make sure you connect before using.

    Servers don't typically connect, clients do, and neither one can control whether or not the other side closes. Qt will fire a signal and tell me, but relying on that still means I have to check state before every send, if Qt will not report to me that a send was attempted on a disconnected socket.

    So we've either got to:
    Check state before every single send
    or
    Be informed when a send is attempted on a disconnected socket

    I'd hope B was possible, but it doesn't seem like I can get any agreement on an official answer of how Qt will inform me.

    We've got a slot for errors, but it doesn't fire in this case. If not in this case, than In what case will it fire? Is it working at all? Did I not rig it up right? How can I test it?Help me get a test together by giving me a condition.

    Qt also gives me a return of bytes written when the send is called. However the documentation says messages won't be fragmented and never describes why or how a number of bytes would be written that is less than the size of the message.

    Furthermore, there has been no explanation of how Qt would even be able to report how many bytes were written, when supposedly in an asynchronous operation, the actual write to the OS's buffer has not occurred at the time the call to send returns!

    I'd really like to get less "guesses" on how it should work and more definitive answers on how it does work. So far in this post I've been told

    • Use the signal
    • Use the return value
    • Use neither and check on state yourself
    • Just connect and forget about it

    Now surely, the authors of the API had only one thing in mind and the others are incorrect guesses. Don't get me wrong, I appreciate attempts at help, but I need some level of confidence that I am doing the right thing.



  • In my testing, it sure looks like the error slot never gets called no matter what. There has to be something wrong with the way it is registered.

    On QAbstractSocket::Error code is connection refused. So, I fired up my code while trying to connect to a bad url. It still did not fire.

    So, I think we've got to get this slot working before we assume the error signal doesn't fire when trying to send in a disconnected state.

    I had registered it like so:

    QObject::connect(m_qtWebsocket,
                         QOverload<QAbstractSocket::SocketError>::of(&QWebSocket::error),
                         this,
                         &WebsocketClientQtImpl::onError);
    

    and it looks like so:

    void WebsocketClientQtImpl::onError(QAbstractSocket::SocketError error)
    {
         std::string errorMessageAsString = m_qtWebsocket->errorString().toStdString();
    }
    

    Did I not call connect correctly? I did as it was found on the docs:
    https://doc.qt.io/qt-5/qwebsocket.html#error-1


  • Lifetime Qt Champion

    I would expect the connection refused error when trying to connect, not later when sending data. So connect to the signal directly after creating the socket.



  • Did a minimal example for you guys today:

        #include <QCoreApplication>
        #include <QObject>
        #include <QWebSocket>
        #include <iostream>
        
        class Client : public QObject
        {
        Q_OBJECT
        public:
            explicit Client(const QUrl &url);
            ~Client();
        
            void connect();
            void send(const std::string & message);
        
        private Q_SLOTS:
        
            void onConnected();
            void onClosed();
            void onError(QAbstractSocket::SocketError errorCode);
        
        private:
            QWebSocket * m_webSocket;
            QUrl m_url;
        };
        
        Client::Client(const QUrl &url)
            :
            QObject(),
            m_url(url)
        {
            m_webSocket = new QWebSocket();
            QObject::connect(m_webSocket, &QWebSocket::connected, this, &Client::onConnected);
            QObject::connect(m_webSocket, &QWebSocket::disconnected, this, &Client::onClosed);
            QObject::connect(m_webSocket, QOverload<QAbstractSocket::SocketError>::of(&QWebSocket::error), this, &Client::onError);
        }
        
        Client::~Client()
        {
            delete m_webSocket;
        }
        
        void Client::connect()
        {
            m_webSocket->open(m_url);
        }
        
        void Client::send(const std::string & message)
        {
            qint64 numbytesWritten = m_webSocket->sendTextMessage(QString::fromStdString(message));
            std::cout << "Wrote " << numbytesWritten << " bytes" << std::endl;
        }
        
        void Client::onConnected()
        {
            std::cout << "Connected" << std::endl;
        }
        
        void Client::onClosed()
        {
            std::cout << "Closed" << std::endl;
        }
        
        void Client::onError(QAbstractSocket::SocketError errorCode)
        {
            std::cout << "Error: " << errorCode << std::endl;
        }
        
        int main(int argc, char ** argv)
        {
            QCoreApplication app(argc, argv);
        
            //QUrl url("ws://echo.websocket.org");
            QUrl url("ws://thisisnotavalidurl.com:5000");
            Client client(url);
            //client.connect();
            client.send("Test message");
        
            return app.exec();
        }
        
        #include "main.moc"
    

    If you do the invalid url and try to connect the error callback is called, so that works. However, if you run it it as is above, without connecting, the error callback is never called.

    I can only conclude that send is not even an async operation in Qt and they intend for the return value to be the only indicication.


Log in to reply