QAbstractSocket error signal not emitted



  • Hi,
    I have a class which uses QTCPSocket. I create a tcp socket and connect the error signal to a slot in my class. All works fine, but no error() is emitted. The code is very simple, in the constructor I typed:

    m_socket = new QTcpSocket(this);
    connect(m_socket, &QTcpSocket::connected, this, &myTCPSocket::connected);
    connect(m_socket, &QTcpSocket::disconnected, this, &myTCPSocket::disconnected);
    connect(m_socket, &QTcpSocket::readyRead, this, &myTCPSocket::readyRead);
    connect(m_socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(error(QAbstractSocket::SocketError)));
    

    and this is my error SLOT:

    void myTCPSocket::error(QAbstractSocket::SocketError socketError)
    {
        qDebug() << socketError;
    }
    

    I have never seen the error signal emitted. Is there something other to do?


  • Qt Champions 2016

    It looks correct. If there is a problem with the signal-slot connection, you should check your debug output window, where Qt will report any problems.

    EDIT:
    Have you registered QAbstractSocket::SocketError as a metatype?



  • @kshegunov

    It looks correct. If there is a problem with the signal-slot connection, you should check your debug output window, where Qt will report any problems.
    

    I know what you're talking about, but this time there are no warning in the debug window.

    Have you registered QAbstractSocket::SocketError as a metatype?
    

    mmm, this sounds new to me. Please, would you explain a but more? Why I should registed QAbstractSocket::SocketError? Isn't it just an enum?


  • Moderators

    @Mark81
    Checkout in the documentation above the note. I could not believe it, but @kshegunov is right.



  • @koahnig
    Yeah, I see. I wonder why, though.
    Anyway, I added the following lines to my code:

    Q_DECLARE_METATYPE(QAbstractSocket::SocketError)
    qRegisterMetaType<QAbstractSocket::SocketError>("QAbstractSocket::SocketError");
    

    But it returns this error:

    error: a template declaration cannot appear at block scope
    

    So I moved the Q_DECLARE_METATYPE line outside the class. Now I get:

    redefinition of 'struct QMetaTypeId<QAbstractSocket::SocketError>'
    

    I'm reading the docs about Q_DECLARE_METATYPE, I'm sorry, but I cannot understand how to use it. I don't see an example.
    Thank you

    EDIT:
    Another think I don't understand. The docs says:

    QAbstractSocket::SocketError is not a registered metatype, so for queued connections, you will have to register it with Q_DECLARE_METATYPE() and qRegisterMetaType().
    
    

    but at the end of QAbstractSocket.h I see:

    Q_DECLARE_METATYPE(QAbstractSocket::SocketState)
    Q_DECLARE_METATYPE(QAbstractSocket::SocketError)
    

    So why I have to declare them another time?



  • I believe it goes like this:

    Q_DECLARE_METATYPE says that a type is recognized by the Qt type system but it doesn't define the necessary code to do that. The necessary code has to be hooked into the Qt type system. Because the QtNetwork library is separate from the QtCore library, the QtCore library cannot define the necessary code because it would create a dependency on the QtNetwork library.

    So you have to register the code in your application if you want pass the types via signals and slots which is one important part of the Qt type system. Qt has to know how to pack and unpack types so that they can be marshaled and un-marshaled through the message queues.

    Even though the necessary registration could be done in the QtNetwork library in a library startup routine, I don't think it is since the Qt networking classes can be used without signals and slots and an application doing that would not want all the Qt type system code pulled in.


  • Moderators

    @Mark81
    I had wondered about @kshegunov 's remark. Therefore, I looked it up and found the text section to my surprise.

    However, the "and" is wrong as far as I know, you should use either one but not both.
    qRegisterMetaType and Q_DECLARE_METATYPE .

    The other things is that you have mentioned that there has been no warning in a debug window, but you should see one when the type is not registered. Therefore, try again without registration and if there is a warning.
    Since you checked already the header file and a declaration is there, this is pointing towards a bug in documentation.

    And you are right another declaration shall not be required then.

    However, coming back top your initial problem. Just to be sure. Did you check with an error condition?


  • Qt Champions 2016

    @Mark81
    Actually you'll probably need only Q_DECLARE_METATYPE as this is done at compile time - exposing the type to the metatype system (I know it is an enum but it's needed for the QVariant and the like). qRegisterMetaType you'll need if creating objects by class name dynamically, and it seems for queued connections, generally you won't need to call that function, but I suggest you do.

    @koahnig
    Directly from the documentation: "Adding a Q_DECLARE_METATYPE() makes the type known to all template based functions, including QVariant. Note that if you intend to use the type in queued signal and slot connections or in QObject's property system, you also have to call qRegisterMetaType() since the names are resolved at runtime."
    Sometimes you need both.



  • @koahnig
    It would be interesting to know when the Q_DECLARE_METATYPE lines at the bottom of QAbstractSocket.h were added. Perhaps the docs was not updated after that, so now it should look like: "QAbstractSocket::SocketError is a declared but not a registered metatype, so for queued connections, you will have to register it with qRegisterMetaType()."
    It's weird no one else in the world has ever used this signal!

    Anyway, to test the error signal I'm simply trying to connect to my server (which works under normal conditions) with the Ethernet cable disconnected.

    I'm expecting at least one of the following errors:

    QAbstractSocket::ConnectionRefusedError	0	The connection was refused by the peer (or timed out).
    QAbstractSocket::HostNotFoundError	    2	The host address was not found.
    QAbstractSocket::SocketTimeoutError	    5	The socket operation timed out.
    QAbstractSocket::NetworkError	        7	An error occurred with the network (e.g., the network cable was accidentally plugged out).
    

    I also tried to connect before and then unplug the network cable. Nothing.



  • Oh dear! It works Even without qRegisterMetaType() - so the docs are definitely wrong.
    But it takes a huge time before fire, something about 30 s! This if I try to connect without the cable. After 30 seconds I get the NetworkError message.

    On the other hand, if I establish the connection and then I unplug the cable nothing happens, even after few minutes.
    Anyway I cannot wait for such a long time to inform the user the device is not connected anymore. I'm afraid I need to implement by myself a sort of software "ping" to be sure the remote device is still there. What a pity.



  • The default time out on QTcpSocket is 30s, you can reduce it if you want more responsive failure detection but you should be sure that you do not use a timeout less than normal round trip latency to the server.

    The docs are not wrong, you only need to register the types for Queued signal/slot connections as several have said above. Non-queued signal/slot connections are simply member function calls.


  • Moderators

    To add to @bsomervi there you have the default waiting time of 30 seconds

    @bsomervi said:

    The docs are not wrong, you only need to register the types for Queued signal/slot connections as several have said above. Non-queued signal/slot connections are simply member function calls.

    This is the first time I have seen such a difference for signal-slot connections. However, certainly I know only a small fraction of the documentation.
    If you say so, I assume that you are correct about different behaviour for queued and non-queued connections.
    The documentation is at least a bit ambiguous in that respect and the sentences might require a revision for clarity.


  • Qt Champions 2016

    @koahnig said:

    This is the first time I have seen such a difference for signal-slot connections.

    It pops out every time you write a class that you intent to use as a signal/slot parameter in multithreaded application.


  • Moderators

    @kshegunov

    That there is a difference between queued and non-queued is clear.
    I had meant that there is difference in registered objects between queued and non-queued connections.
    I came across the need to register for my own classes. So far I thought that all Qt classes are registered alreay. Thought to have read a reference somewhere, but also quite a while ago.



  • @bsomervi

    The default time out on QTcpSocket is 30s, you can reduce it if you want more responsive failure detection
    

    English is not my primary language, thus I apologize if sometimes it's hard to understand what I'm reading. Anyway I read through the docs and I cannot find how to reduce this timeout. As @koahnig said I could use the waitForConnected() function but: 1. the docs say it may fail randomly on Windows, 2. it blocks the execution of my code, 3. it could work only during connection, but it isn't useful to detect a failure (i.e. the cable disconnected after).

    I cannot find a method like: setTimeout() or similar.

    Currently the only way I found is to periodically send back and forth a message: when I don't receive the answer in few seconds I assume the connection is lost. I hate this approach, though! I'm pretty sure the system knows if a TCP socket isn't alive anymore!



  • @Mark81 Sorry I have misled you, I was confusing the timeout on the wait...() functions with the asynchronous signals. You do not want the wait...() functions in the GUI thread as they block.

    The first thing to note is that normal TCP/IP will retry 12 times to send a data segment taking up to 9 minutes before it causes an error.

    I think you have two choices in the normal TCP/IP framework.

    If you are sending data and expecting a reply, you can start a single shot timer that is cancelled if the reply is received but causes your communications failed code to run when it times out.

    If you are just waiting for data then you will get no notification of errors as TCP/IP will wait forever on a disconnected circuit. So in this case you must have your server send you periodic "heartbeat" data to confirm its reachability.



Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.