Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. QTcpServer sometimes generates two newConnection() signals for the same connection

QTcpServer sometimes generates two newConnection() signals for the same connection

Scheduled Pinned Locked Moved General and Desktop
5 Posts 2 Posters 2.9k Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • G Offline
    G Offline
    Gallaecio
    wrote on last edited by
    #1

    This started with a failing test in "libmediawiki":https://projects.kde.org/projects/extragear/libs/libmediawiki. I though it was a race condition between a KJob and a QTcpServer, and "asked in the KDE forums":https://forum.kde.org/viewtopic.php?f=64&t=110250. There, I was suggested to ask in the KDE development mailing list. There, "it was pointed out":http://lists.kde.org/?l=kde-devel&m=136266672827472&w=2 that there was no race condition, just that I was expecting QTcpServer to behave one way, and it is behaving differently. This last answer gave me a way to handle the issue. Now, I would like to understand it.

    So, we have the following main function:

    @
    // main.cpp
    #include <QtCore/QCoreApplication>
    #include <QtNetwork/QNetworkAccessManager>
    #include <QtNetwork/QNetworkReply>
    #include "fakeserver.h"

    int main(int argc, char* argv[])
    {
    QCoreApplication a(argc, argv);

    QThread *serverThread = new QThread();
    FakeServer *fakeserver = new FakeServer;
    QObject::connect(serverThread, SIGNAL(started()), fakeserver, SLOT(run()));
    QObject::connect(serverThread, SIGNAL(finished()), fakeserver, SLOT(deleteLater()));
    fakeserver->moveToThread(serverThread);
    serverThread->start();
    
    QNetworkAccessManager manager;
    
    for (int i = 0; i < 10000; i++) {
        QUrl url("http://127.0.0.1:12566");
        QNetworkRequest request(url);
        request.setHeader(QNetworkRequest::ContentTypeHeader, QString("application/x-www-form-urlencoded%1").arg(i));
        QNetworkReply *reply = manager.post( request, "aasdf" );
        while (!reply->isFinished())
          qApp->processEvents();
        reply->close();
        reply->deleteLater();
    }
    
    serverThread->quit();
    
    return 0;
    

    }
    @

    The function starts an instance of FakeServer in a separated thread, and performs 10000 request to the URL http://127.0.0.1:12566. The FakeServer manages a QTcpServer that listens on that address. This is the FakeServer implementation:

    @
    // fakeserver.h
    #ifndef SERVER_H
    #define SERVER_H

    #include <QtCore/QMutex>
    #include <QtCore/QString>
    #include <QtCore/QStringList>
    #include <QtCore/QThread>
    #include <QtNetwork/QTcpServer>
    #include <QtNetwork/QTcpSocket>

    class FakeServer : public QObject
    {
    Q_OBJECT

    public:

    FakeServer(QObject* const parent = 0);
    ~FakeServer();
    

    private Q_SLOTS:

    void newConnection();
    void dataAvailable();
    void run();
    

    private:

    void writeServerPart();
    void readClientPart();
    

    private:

    QSet<QString> m_allRequests;
    QTcpServer*                m_tcpServer;
    mutable QMutex             m_mutex;
    QTcpSocket*                m_clientSocket;
    

    };

    #endif // SERVER_H
    @

    @
    // fakeserver.cpp
    #include "fakeserver.h"

    #include <QtCore/QDebug>

    FakeServer::FakeServer(QObject* const parent)
    : QObject( parent )
    {
    m_clientSocket = 0;
    m_tcpServer = 0;
    }

    FakeServer::~FakeServer()
    {
    delete m_clientSocket;
    delete m_tcpServer;
    }

    void FakeServer::newConnection()
    {
    QMutexLocker locker(&m_mutex);
    m_clientSocket = m_tcpServer->nextPendingConnection();

    connect(m_clientSocket, SIGNAL(readyRead()),
            this, SLOT(dataAvailable()));
    

    }

    void FakeServer::dataAvailable()
    {
    QMutexLocker locker(&m_mutex);
    readClientPart();
    writeServerPart();
    }

    void FakeServer::run()
    {
    m_tcpServer = new QTcpServer();

    if ( !m_tcpServer->listen( QHostAddress( QHostAddress::LocalHost ), 12566 ) )
    {
    }
    
    connect(m_tcpServer, SIGNAL(newConnection()),
            this, SLOT(newConnection()));
    

    }

    void FakeServer::writeServerPart()
    {
    QString response = "HTTP/1.0 200 Ok\r\nContent-Type: text/html; charset="utf-8"\r\n\r\n<api><error code="notext" info="" /> </api>";
    m_clientSocket->write( response.toLocal8Bit() );
    m_clientSocket->close();
    }

    void FakeServer::readClientPart()
    {
    QString data;
    while (m_clientSocket->bytesAvailable())
    {
    data += m_clientSocket->readAll();
    }
    if (m_allRequests.contains(data)) {
    qDebug() << "Already got this request!!!!!!!!!!!" << data;
    } else {
    qDebug() << "Add request" << m_clientSocket << data;
    m_allRequests << data;
    }
    }
    @

    If you run this code, you will see that now and then the 62nd line gets called. This is because, now and then, the newConnection() signal is emitted twice for the same connection (as far as I understand).

    Does anyone know why that is happening? And, is it because the code is wrong at some point, or because that is just the way QTcpServer is meant to work?

    Note: The code was written by Albert Astals Cid. See the "KDE development mailing list archive":http://lists.kde.org/?l=kde-devel&m=136266672827472&w=2.

    1 Reply Last reply
    0
    • T Offline
      T Offline
      tucnak
      wrote on last edited by
      #2

      Hello, ~Gallaecio.

      Welcome to Qt Developer Network.

      Can you, please, add this line right in FakeServer::newConnection()?

      @
      qDebug() << "New connection signal is emitted";
      @

      1 Reply Last reply
      0
      • G Offline
        G Offline
        Gallaecio
        wrote on last edited by
        #3

        Oh, right. It’s the socket that emits * readyRead()* twice. Still, is it normal that readyRead() is emitted more than once for the same data?

        1 Reply Last reply
        0
        • T Offline
          T Offline
          tucnak
          wrote on last edited by
          #4

          [quote author="Gallaecio" date="1362768257"]Oh, right. It’s the socket that emits * readyRead()* twice. Still, is it normal that readyRead() is emitted more than once for the same data?[/quote]

          No, it isn't. It should be emitted only once. There is a problem in your code, just 'cause Qt code is debugged well :-)

          1 Reply Last reply
          0
          • G Offline
            G Offline
            Gallaecio
            wrote on last edited by
            #5

            [quote author="tucnak" date="1362768836"]There is a problem in your code, just 'cause Qt code is debugged well :-)[/quote]

            Sorry, but I don’t know what you mean. I get that you say that the code is not right, which is not unexpected. The problem is that I don’t know what my mistake is. And “just ‘cause Qt code is debugged well :-)” does not mean anything to me. Could you please be more specific?

            In the meantime, I added a qDebug() after the mutex in dataAvailable() and another one after the mutex in newConnection(). Eventually, the result is:

            bq. FakeServer::newConnection()
            FakeServer::dataAvailable()
            Added request
            FakeServer::newConnection()
            FakeServer::dataAvailable()
            Added request
            FakeServer::newConnection()
            FakeServer::dataAvailable()
            Already got this request!!!!!!!!!!!
            FakeServer::newConnection()
            FakeServer::newConnection()
            FakeServer::dataAvailable()
            Added request

            1 Reply Last reply
            0

            • Login

            • Login or register to search.
            • First post
              Last post
            0
            • Categories
            • Recent
            • Tags
            • Popular
            • Users
            • Groups
            • Search
            • Get Qt Extensions
            • Unsolved