Uploaded image for project: 'Qt'
  1. Qt
  2. QTBUG-140135

QTcpSocket gives an error but TCP connection is established

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Unresolved
    • Icon: P2: Important P2: Important
    • None
    • 6.9.2
    • Network: Sockets
    • None
    • Windows

      I'd like to connect to a TCP server. I use QTcpSocket::connectToHost(). There is no problem if the server is launched before my app. But if it's launched later, we can end up in a strange situation: QTcpSocket sends errorOccurred signal but the TCP connection is established successfuly.

      It's due to the algorithm Qt uses to make a connection. First of all for each resolved address Qt makes two connection attempts. First one is simple. Qt calls WSAconnect() to start connection and after 2 seconds (on Windows) it calls WSAconnect() again to check connection state. If it failed, native socket descriptor is closed. But the second attempt is different. There when the state check is made, socket is not closed. If the other host didn't reply, Qt reports error, but native socket still tries to connect. If it succeeds, there is no notification from Qt to app. The app thinks that connection failed but it is live. So the problem is that Qt doesn't close the socket when error occurs. The interesting thing is that an app can't do it by itself instead. Calling close() or disconnectFromHost() doesn't help because the socket is in UnconectedState and resetSocketLayer() is not called inside the QAbstractClass code. The fix is to close the native socket after 2nd attempt just as it is closed after 1st attempt.

      The problem is easy to reproduce, here is a simple test program which shows the issue.

      #include <QtCore>
      #include <QtNetwork>int main(int argc, char* argv[]) {
          QCoreApplication a(argc, argv);
          QTcpSocket socket;
          QObject::connect(&socket, &QTcpSocket::connected, [&](){
              qDebug() << QDateTime::currentDateTime().toString("hh:mm:ss,zzz") << "Client connected";
          });
          QObject::connect(&socket, &QTcpSocket::errorOccurred, [&socket](QAbstractSocket::SocketError err){
              qDebug() << QDateTime::currentDateTime().toString("hh:mm:ss,zzz") << "Socket error:" << socket.errorString();
              socket.disconnectFromHost();
          });
          
          socket.connectToHost("127.0.0.1", 60032);
          qDebug() << QDateTime::currentDateTime().toString("hh:mm:ss,zzz") << "Connecting";
          QTimer timer;
          QTcpServer server;
          QObject::connect(&timer, &QTimer::timeout, [&](){
              QObject::connect(&server, &QTcpServer::newConnection, [&](){
                  qDebug() << QDateTime::currentDateTime().toString("hh:mm:ss,zzz") << "Server connected";
              });
              server.listen(QHostAddress::LocalHost, 60032);
              qDebug() << QDateTime::currentDateTime().toString("hh:mm:ss,zzz") << "Listening";
          });
          timer.setSingleShot(true);
          timer.start(5000);
          return a.exec();
      }
      

      Output with 5 seconds delay:
      "14:02:42,623" Connecting
      "14:02:46,695" Socket error: "Connection refused"
      "14:02:47,678" Listening
      "14:02:47,710" Server connected

      Output with 3 seconds delay:
      "14:05:23,723" Connecting
      "14:05:26,742" Listening
      "14:05:27,250" Server connected
      "14:05:27,252" Client connected

        1. qt.png
          71 kB
          Grzegorz
        No reviews matched the request. Check your Options in the drop-down menu of this sections header.

            manordheim Mårten Nordheim
            grzegorzn Grzegorz
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

              Created:
              Updated:

                There are no open Gerrit changes