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. QTcpSocket client, write problem...
Forum Updated to NodeBB v4.3 + New Features

QTcpSocket client, write problem...

Scheduled Pinned Locked Moved Unsolved General and Desktop
41 Posts 7 Posters 5.2k Views 3 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.
  • SPlattenS SPlatten

    @JonB , Thank you, here is my message handler:

    static void qDebugMsgHandler(QtMsgType type, const QMessageLogContext& context, const QString& strMsg) {
        if ( clsDebugService::blnTerminating() == true ) {
        //Application is terminating, do not add anything else to the stack
            return;
        }
    //    static const QString scstrQJsonObject("QJsonObject(");
        static const QChar scqcCarriageReturn('\n')
                          ,scqcCloseBracket(')')
                          ,scqcComma(',')
                          ,scqcOpenBracket('(');
        static QString sstrLastFile, sstrLastFunction;
        static long slngLastLine = -1;
        clsDebugService* pService = clsDebugService::pGetService();
        quint16 uint16DebugLevel = clsDebugService::mscintDefaultLevel
               ,uint16MsgOffset;
        QString strFile, strFunction, strInfo, strPrefix;
        int intLevelDelimiterIdx = -1;
        //Look for debug level delimiter: \x2, NOTE we cannot use indexOf to locate it!
        static const char ccDebugLevelDelimiter = (clsDebugService::msccDebugLevelDelimiter.toLatin1() + '0');
        for( int i=0; i<strMsg.length() - 3; i++ ) {
            if ( strMsg[i + 1].toLatin1() == '\\'
              && strMsg[i + 2].toLatin1() == 'x'
              && strMsg[i + 3].toLatin1() == ccDebugLevelDelimiter ) {
                intLevelDelimiterIdx = ++i;
                break;
            }
        }
        if ( intLevelDelimiterIdx > 0 ) {
        //Yes, its the debug level
            uint16DebugLevel = strMsg.midRef(0, intLevelDelimiterIdx).toUInt();
        //Offset to start of message
            uint16MsgOffset = intLevelDelimiterIdx + 3;
        } else {
            uint16MsgOffset = 0;
        }
        if ( uint16DebugLevel > clsDebugService::mscintDefaultLevel ) {
        //Do nothing debug level is higher than this messages level
            return;
        }
        //Start with time stamp
        QTime tmNow = QTime::currentTime();
        strPrefix = tmNow.toString(Qt::ISODateWithMs);
        strPrefix += " ";
        switch( type ) {
        case QtCriticalMsg:
            strPrefix += "C";
            break;
        case QtDebugMsg:
            strPrefix += "D";
            break;
        case QtFatalMsg:
            strPrefix += "F";
            break;
        case QtInfoMsg:
            strPrefix += "I";
            break;
        case QtWarningMsg:
            strPrefix += "W";
            break;
        }
        if ( strPrefix.isEmpty() != true ) {
            strPrefix += ":";
        }
        //Split message into lines?
        QStringList slstParts = strMsg.mid(uint16MsgOffset).split(scqcCarriageReturn);
        quint16 uint16Parts = slstParts.length();
        long lngLine = 0;
        for( quint16 uint16Part=0; uint16Part<uint16Parts; uint16Part++ ) {
            QString strOutput(strPrefix), strPart;
    
            if ( slstParts.length() > 1 ) {
                strPart = slstParts[uint16Part];
    
                if ( strPart.startsWith(scqcComma) ) {
                    strPart = strPart.remove(scqcComma);
                }
                if ( uint16Part == 0 && strPart.startsWith(scqcOpenBracket) ) {
                    strPart = clsDebugService::msccSpace + strPart.mid(1);
                }
                if ( uint16Part == uint16Parts && strPart.endsWith(scqcCloseBracket) ) {
                    strPart = strPart.remove(scqcCloseBracket);
                }
            } else {
                strPart = slstParts[uint16Part];
            }
            if ( strPart.isEmpty() == true ) {
                continue;
            }
    /*Is this used???        if ( strPart.startsWith(scstrQJsonObject) ) {
        //Message contains a JSON object, extract the details
                int intLength = strPart.length() - (scstrQJsonObject.length() + 1);
                QString strJSON = strPart.mid(scstrQJsonObject.length(), intLength);
                QJsonDocument objDoc = QJsonDocument::fromJson(strJSON.toUtf8());
    
                if ( objDoc.isNull() ) {
                    return;
                }
                QJsonObject objJSON = objDoc.object();
                QString strLine(objJSON.take("line").toString());
                strFile = objJSON.take("file").toString();
                lngLine = strLine.toLong();
                strInfo = objJSON.take("msg").toString();
                type = static_cast<QtMsgType>(objJSON.take("type").toInt());
            } else */{
                uint32_t uint32Line = 0;
    
                if ( pService->blnGetOriginDetails(strFile, uint32Line) == true ) {
                    lngLine = static_cast<long>(uint32Line);
                }
                if ( context.function ) {
                    strFunction = QString(context.function);
                    strFunction = strFunction.mid(0, strFunction.indexOf(clsDebugService::msccBrktOpen));
                }
                strInfo = strPart;
            }
            if ( strInfo.trimmed().isEmpty() == true || strInfo.compare(scqcCloseBracket) == 0 ) {
                continue;
            }
            if ( uint16Part == 0 ) {
                if ( lngLine >= 0 && !(slngLastLine == lngLine
                                  && strFile.compare(sstrLastFile) == 0
                                  && sstrLastFunction.compare(strFunction) == 0) ) {
                    sstrLastFile = strFile;
                    slngLastLine = lngLine;
                    sstrLastFunction = strFunction;
    
                    if ( lngLine > 0 ) {
                        strOutput += QString("L%1").arg(lngLine, clsDebugService::mscintLineNoLength
                                                               , clsDebugService::mscintLineNoBase, QChar('0'));
                    }
                    if ( strFile.length() > 0 ) {
                        strOutput += QString("F%1").arg(strFile);
                    }
                    if ( strFunction.length() > 0 ) {
                        strOutput += "[" + strFunction + "]";
                    }
                }            
                if ( strInfo.isEmpty() != true ) {
                    strOutput += strInfo;
                }
                pService->blnPushDebug(strOutput);
            } else if ( uint16Parts > 1 ) {
                strOutput += strInfo;
                pService->blnPushDebug(strOutput);
            }
        }
    }
    

    I think the issue here is that it crashes before the message queue is processed, I'll try putting breakpoints on the message types when QtCriticalMsg, QtFatalMsg and QtWarningMsg.

    So far this is what I've found:

    QSocketNotifier: Socket notifiers cannot be enabled or disabled from another thread
    
    JonBJ Offline
    JonBJ Offline
    JonB
    wrote on last edited by
    #12

    @SPlatten
    The fact that QMessageLogger::warning is calling abort() does not look right. With your extremely complex-looking code there, Im wonder whether it isn't falling over in your own code! You handler at this level should be much simpler, IMHO! Anyway, put in judiciois breakpoints and see of you can break where you can view the messages from QSocketNotifier::setEnabled().

    SPlattenS kshegunovK 2 Replies Last reply
    0
    • JonBJ JonB

      @SPlatten
      The fact that QMessageLogger::warning is calling abort() does not look right. With your extremely complex-looking code there, Im wonder whether it isn't falling over in your own code! You handler at this level should be much simpler, IMHO! Anyway, put in judiciois breakpoints and see of you can break where you can view the messages from QSocketNotifier::setEnabled().

      SPlattenS Offline
      SPlattenS Offline
      SPlatten
      wrote on last edited by
      #13

      @JonB , I think you posted before I edited, see the end of the last post.

      Kind Regards,
      Sy

      1 Reply Last reply
      0
      • SPlattenS SPlatten

        @JonB , Thank you, here is my message handler:

        static void qDebugMsgHandler(QtMsgType type, const QMessageLogContext& context, const QString& strMsg) {
            if ( clsDebugService::blnTerminating() == true ) {
            //Application is terminating, do not add anything else to the stack
                return;
            }
        //    static const QString scstrQJsonObject("QJsonObject(");
            static const QChar scqcCarriageReturn('\n')
                              ,scqcCloseBracket(')')
                              ,scqcComma(',')
                              ,scqcOpenBracket('(');
            static QString sstrLastFile, sstrLastFunction;
            static long slngLastLine = -1;
            clsDebugService* pService = clsDebugService::pGetService();
            quint16 uint16DebugLevel = clsDebugService::mscintDefaultLevel
                   ,uint16MsgOffset;
            QString strFile, strFunction, strInfo, strPrefix;
            int intLevelDelimiterIdx = -1;
            //Look for debug level delimiter: \x2, NOTE we cannot use indexOf to locate it!
            static const char ccDebugLevelDelimiter = (clsDebugService::msccDebugLevelDelimiter.toLatin1() + '0');
            for( int i=0; i<strMsg.length() - 3; i++ ) {
                if ( strMsg[i + 1].toLatin1() == '\\'
                  && strMsg[i + 2].toLatin1() == 'x'
                  && strMsg[i + 3].toLatin1() == ccDebugLevelDelimiter ) {
                    intLevelDelimiterIdx = ++i;
                    break;
                }
            }
            if ( intLevelDelimiterIdx > 0 ) {
            //Yes, its the debug level
                uint16DebugLevel = strMsg.midRef(0, intLevelDelimiterIdx).toUInt();
            //Offset to start of message
                uint16MsgOffset = intLevelDelimiterIdx + 3;
            } else {
                uint16MsgOffset = 0;
            }
            if ( uint16DebugLevel > clsDebugService::mscintDefaultLevel ) {
            //Do nothing debug level is higher than this messages level
                return;
            }
            //Start with time stamp
            QTime tmNow = QTime::currentTime();
            strPrefix = tmNow.toString(Qt::ISODateWithMs);
            strPrefix += " ";
            switch( type ) {
            case QtCriticalMsg:
                strPrefix += "C";
                break;
            case QtDebugMsg:
                strPrefix += "D";
                break;
            case QtFatalMsg:
                strPrefix += "F";
                break;
            case QtInfoMsg:
                strPrefix += "I";
                break;
            case QtWarningMsg:
                strPrefix += "W";
                break;
            }
            if ( strPrefix.isEmpty() != true ) {
                strPrefix += ":";
            }
            //Split message into lines?
            QStringList slstParts = strMsg.mid(uint16MsgOffset).split(scqcCarriageReturn);
            quint16 uint16Parts = slstParts.length();
            long lngLine = 0;
            for( quint16 uint16Part=0; uint16Part<uint16Parts; uint16Part++ ) {
                QString strOutput(strPrefix), strPart;
        
                if ( slstParts.length() > 1 ) {
                    strPart = slstParts[uint16Part];
        
                    if ( strPart.startsWith(scqcComma) ) {
                        strPart = strPart.remove(scqcComma);
                    }
                    if ( uint16Part == 0 && strPart.startsWith(scqcOpenBracket) ) {
                        strPart = clsDebugService::msccSpace + strPart.mid(1);
                    }
                    if ( uint16Part == uint16Parts && strPart.endsWith(scqcCloseBracket) ) {
                        strPart = strPart.remove(scqcCloseBracket);
                    }
                } else {
                    strPart = slstParts[uint16Part];
                }
                if ( strPart.isEmpty() == true ) {
                    continue;
                }
        /*Is this used???        if ( strPart.startsWith(scstrQJsonObject) ) {
            //Message contains a JSON object, extract the details
                    int intLength = strPart.length() - (scstrQJsonObject.length() + 1);
                    QString strJSON = strPart.mid(scstrQJsonObject.length(), intLength);
                    QJsonDocument objDoc = QJsonDocument::fromJson(strJSON.toUtf8());
        
                    if ( objDoc.isNull() ) {
                        return;
                    }
                    QJsonObject objJSON = objDoc.object();
                    QString strLine(objJSON.take("line").toString());
                    strFile = objJSON.take("file").toString();
                    lngLine = strLine.toLong();
                    strInfo = objJSON.take("msg").toString();
                    type = static_cast<QtMsgType>(objJSON.take("type").toInt());
                } else */{
                    uint32_t uint32Line = 0;
        
                    if ( pService->blnGetOriginDetails(strFile, uint32Line) == true ) {
                        lngLine = static_cast<long>(uint32Line);
                    }
                    if ( context.function ) {
                        strFunction = QString(context.function);
                        strFunction = strFunction.mid(0, strFunction.indexOf(clsDebugService::msccBrktOpen));
                    }
                    strInfo = strPart;
                }
                if ( strInfo.trimmed().isEmpty() == true || strInfo.compare(scqcCloseBracket) == 0 ) {
                    continue;
                }
                if ( uint16Part == 0 ) {
                    if ( lngLine >= 0 && !(slngLastLine == lngLine
                                      && strFile.compare(sstrLastFile) == 0
                                      && sstrLastFunction.compare(strFunction) == 0) ) {
                        sstrLastFile = strFile;
                        slngLastLine = lngLine;
                        sstrLastFunction = strFunction;
        
                        if ( lngLine > 0 ) {
                            strOutput += QString("L%1").arg(lngLine, clsDebugService::mscintLineNoLength
                                                                   , clsDebugService::mscintLineNoBase, QChar('0'));
                        }
                        if ( strFile.length() > 0 ) {
                            strOutput += QString("F%1").arg(strFile);
                        }
                        if ( strFunction.length() > 0 ) {
                            strOutput += "[" + strFunction + "]";
                        }
                    }            
                    if ( strInfo.isEmpty() != true ) {
                        strOutput += strInfo;
                    }
                    pService->blnPushDebug(strOutput);
                } else if ( uint16Parts > 1 ) {
                    strOutput += strInfo;
                    pService->blnPushDebug(strOutput);
                }
            }
        }
        

        I think the issue here is that it crashes before the message queue is processed, I'll try putting breakpoints on the message types when QtCriticalMsg, QtFatalMsg and QtWarningMsg.

        So far this is what I've found:

        QSocketNotifier: Socket notifiers cannot be enabled or disabled from another thread
        
        JonBJ Offline
        JonBJ Offline
        JonB
        wrote on last edited by
        #14

        @SPlatten said in QTcpSocket client, write problem...:

        QSocketNotifier: Socket notifiers cannot be enabled or disabled from another thread

        So that's the original faulting message? Yep, well, you know this is a problem in the code you're writing :)

        1 Reply Last reply
        0
        • J.HilkJ Offline
          J.HilkJ Offline
          J.Hilk
          Moderators
          wrote on last edited by
          #15

          Is this across threads? the forced DirectConnection lets me believe that

          QAbstractStrocket uses internal QTimer objects you're calling onWrite via a forced DirectConnection, that means the write is called from the calling thread and that is != the thread where the socket may live -> QTimers can't be started or stoped from an other thread.

          Possibly the reason for your failed write attempt


          Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct


          Q: What's that?
          A: It's blue light.
          Q: What does it do?
          A: It turns blue.

          SPlattenS 1 Reply Last reply
          1
          • J.HilkJ J.Hilk

            Is this across threads? the forced DirectConnection lets me believe that

            QAbstractStrocket uses internal QTimer objects you're calling onWrite via a forced DirectConnection, that means the write is called from the calling thread and that is != the thread where the socket may live -> QTimers can't be started or stoped from an other thread.

            Possibly the reason for your failed write attempt

            SPlattenS Offline
            SPlattenS Offline
            SPlatten
            wrote on last edited by
            #16

            @J-Hilk , thank you, I've removed the Qt::DirectConnection parameter from the connects and now the warning has gone.

            Kind Regards,
            Sy

            J.HilkJ JonBJ 2 Replies Last reply
            0
            • SPlattenS SPlatten

              @J-Hilk , thank you, I've removed the Qt::DirectConnection parameter from the connects and now the warning has gone.

              J.HilkJ Offline
              J.HilkJ Offline
              J.Hilk
              Moderators
              wrote on last edited by
              #17

              @SPlatten I don't know if QJsonObject is registered with the meta system by default, if not, you'll have to do that yourself, or the connect won't work.

              But you should get compile/runtime warnings if thats the case


              Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct


              Q: What's that?
              A: It's blue light.
              Q: What does it do?
              A: It turns blue.

              SPlattenS 1 Reply Last reply
              0
              • SPlattenS SPlatten

                @J-Hilk , thank you, I've removed the Qt::DirectConnection parameter from the connects and now the warning has gone.

                JonBJ Offline
                JonBJ Offline
                JonB
                wrote on last edited by JonB
                #18

                @SPlatten
                A while back in another of your post threads you were using explicit Qt::DirectConnections, and I said then (and I think others did too), why are you writing this, it will just lead to trouble.

                So why do you ever put Qt::DirectConnection into your connect()s, I just don't get it, it keeps leading to this kind of problem?

                SPlattenS 1 Reply Last reply
                0
                • JonBJ JonB

                  @SPlatten
                  A while back in another of your post threads you were using explicit Qt::DirectConnections, and I said then (and I think others did too), why are you writing this, it will just lead to trouble.

                  So why do you ever put Qt::DirectConnection into your connect()s, I just don't get it, it keeps leading to this kind of problem?

                  SPlattenS Offline
                  SPlattenS Offline
                  SPlatten
                  wrote on last edited by
                  #19

                  @JonB , they are gone now.

                  Kind Regards,
                  Sy

                  JonBJ 1 Reply Last reply
                  0
                  • J.HilkJ J.Hilk

                    @SPlatten I don't know if QJsonObject is registered with the meta system by default, if not, you'll have to do that yourself, or the connect won't work.

                    But you should get compile/runtime warnings if thats the case

                    SPlattenS Offline
                    SPlattenS Offline
                    SPlatten
                    wrote on last edited by
                    #20

                    @J-Hilk , I do register the type.

                    Kind Regards,
                    Sy

                    1 Reply Last reply
                    1
                    • SPlattenS SPlatten

                      @JonB , they are gone now.

                      JonBJ Offline
                      JonBJ Offline
                      JonB
                      wrote on last edited by JonB
                      #21

                      @SPlatten said in QTcpSocket client, write problem...:

                      @JonB , they are gone now.

                      :) May I suggest you never put them in? The default for connect() is DirectConnection, and Qt only changes that to Queued when it sees it's going across threads. At which point as I understand it you need it to do that, so why interfere? :)

                      Might I also suggest you consider simplifying your qDebugMsgHandler()? That's an awful lot of code to potentially go wrong, when you are down in a low-level message handler! And if it does you will lose the original message, as you have seen. At minimum: factor all your stuff out to a separate function, so that qDebugMsgHandler() is lean & clean. And wrap that with a try handler. If it goes doolally, allow the original qDebugMsgHandler() to not fall over but to issue some message in a simple fashion. That way you have some protection for not fouling up and still getting access to the original fault message. Making sure one's low-level error/message handlers do not themselves introduce errors is an important goal.

                      SPlattenS 1 Reply Last reply
                      1
                      • JonBJ JonB

                        @SPlatten said in QTcpSocket client, write problem...:

                        @JonB , they are gone now.

                        :) May I suggest you never put them in? The default for connect() is DirectConnection, and Qt only changes that to Queued when it sees it's going across threads. At which point as I understand it you need it to do that, so why interfere? :)

                        Might I also suggest you consider simplifying your qDebugMsgHandler()? That's an awful lot of code to potentially go wrong, when you are down in a low-level message handler! And if it does you will lose the original message, as you have seen. At minimum: factor all your stuff out to a separate function, so that qDebugMsgHandler() is lean & clean. And wrap that with a try handler. If it goes doolally, allow the original qDebugMsgHandler() to not fall over but to issue some message in a simple fashion. That way you have some protection for not fouling up and still getting access to the original fault message. Making sure one's low-level error/message handlers do not themselves introduce errors is an important goal.

                        SPlattenS Offline
                        SPlattenS Offline
                        SPlatten
                        wrote on last edited by
                        #22

                        @JonB , thank you, the debugHandler works fine and quite sure there is nothing wrong with it, I accept your comments and in the final release it will be disabled altogether.

                        Kind Regards,
                        Sy

                        1 Reply Last reply
                        0
                        • JonBJ JonB

                          @SPlatten
                          The fact that QMessageLogger::warning is calling abort() does not look right. With your extremely complex-looking code there, Im wonder whether it isn't falling over in your own code! You handler at this level should be much simpler, IMHO! Anyway, put in judiciois breakpoints and see of you can break where you can view the messages from QSocketNotifier::setEnabled().

                          kshegunovK Offline
                          kshegunovK Offline
                          kshegunov
                          Moderators
                          wrote on last edited by
                          #23

                          @SPlatten, fix the reason for the warning, so you don't get the warning. In other words, don't enable/disable sockets from different threads.

                          @JonB said in QTcpSocket client, write problem...:

                          The fact that QMessageLogger::warning is calling abort() does not look right.

                          He's running with fatal warnings (as suggested in earlier threads), so it's exactly right!

                          Read and abide by the Qt Code of Conduct

                          SPlattenS 1 Reply Last reply
                          5
                          • kshegunovK kshegunov

                            @SPlatten, fix the reason for the warning, so you don't get the warning. In other words, don't enable/disable sockets from different threads.

                            @JonB said in QTcpSocket client, write problem...:

                            The fact that QMessageLogger::warning is calling abort() does not look right.

                            He's running with fatal warnings (as suggested in earlier threads), so it's exactly right!

                            SPlattenS Offline
                            SPlattenS Offline
                            SPlatten
                            wrote on last edited by
                            #24

                            I think I spoke to soon I still have the problem:

                            QSocketNotifier: Socket notifiers cannot be enabled or disabled from another thread
                            

                            I've modified all my QObject::connect's, ensuring that I am not using Qt::DirectConnection. I'm still getting this message. I've been careful that I am not calling write from any thread, I always emit a write signal which connects to a slot called onWrite which actually does the::

                            qint64 int64Written = mpsckClient->write(arybytMsg);
                            

                            Kind Regards,
                            Sy

                            KroMignonK 1 Reply Last reply
                            0
                            • SPlattenS SPlatten

                              I think I spoke to soon I still have the problem:

                              QSocketNotifier: Socket notifiers cannot be enabled or disabled from another thread
                              

                              I've modified all my QObject::connect's, ensuring that I am not using Qt::DirectConnection. I'm still getting this message. I've been careful that I am not calling write from any thread, I always emit a write signal which connects to a slot called onWrite which actually does the::

                              qint64 int64Written = mpsckClient->write(arybytMsg);
                              
                              KroMignonK Offline
                              KroMignonK Offline
                              KroMignon
                              wrote on last edited by KroMignon
                              #25

                              @SPlatten said in QTcpSocket client, write problem...:

                              I think I spoke to soon I still have the problem:
                              QSocketNotifier: Socket notifiers cannot be enabled or disabled from another thread

                              As an experimented developer, you should know that multithreading can solve problems but always introduce new problems ;)

                              When using QObject based classes, you should always ensure that you are using them in the thread in which they have be created / moved.
                              So, are you sure qint64 int64Written = mpsckClient->write(arybytMsg); is done in the right thread (mpsckClient->thread() == QThread::currentThread()).

                              It is an old maxim of mine that when you have excluded the impossible, whatever remains, however improbable, must be the truth. (Sherlock Holmes)

                              SPlattenS 1 Reply Last reply
                              3
                              • KroMignonK KroMignon

                                @SPlatten said in QTcpSocket client, write problem...:

                                I think I spoke to soon I still have the problem:
                                QSocketNotifier: Socket notifiers cannot be enabled or disabled from another thread

                                As an experimented developer, you should know that multithreading can solve problems but always introduce new problems ;)

                                When using QObject based classes, you should always ensure that you are using them in the thread in which they have be created / moved.
                                So, are you sure qint64 int64Written = mpsckClient->write(arybytMsg); is done in the right thread (mpsckClient->thread() == QThread::currentThread()).

                                SPlattenS Offline
                                SPlattenS Offline
                                SPlatten
                                wrote on last edited by
                                #26

                                @KroMignon I thought that one of the benefits of using signals and slots is that you can be assured that they are thread safe?

                                Kind Regards,
                                Sy

                                KroMignonK 1 Reply Last reply
                                0
                                • SPlattenS SPlatten

                                  @KroMignon I thought that one of the benefits of using signals and slots is that you can be assured that they are thread safe?

                                  KroMignonK Offline
                                  KroMignonK Offline
                                  KroMignon
                                  wrote on last edited by KroMignon
                                  #27

                                  @SPlatten said in QTcpSocket client, write problem...:

                                  I thought that one of the benefits of using signals and slots is that you can be assured that they are thread safe?

                                  Yes it is, but it depends how you are doing it.

                                  QObject::connect(srcObject, SIGNAL(), destObject, SLOT()) will ensure SLOT() will run in destObject work thread, when signal is emitted.

                                  EDIT:
                                  but
                                  QObject::connect(srcObject, SIGNAL(), destObject, SLOT(), Qt::DirectConnection) will run SLOT() in thread from which signal has been emitted.

                                  It is an old maxim of mine that when you have excluded the impossible, whatever remains, however improbable, must be the truth. (Sherlock Holmes)

                                  SPlattenS 1 Reply Last reply
                                  5
                                  • KroMignonK KroMignon

                                    @SPlatten said in QTcpSocket client, write problem...:

                                    I thought that one of the benefits of using signals and slots is that you can be assured that they are thread safe?

                                    Yes it is, but it depends how you are doing it.

                                    QObject::connect(srcObject, SIGNAL(), destObject, SLOT()) will ensure SLOT() will run in destObject work thread, when signal is emitted.

                                    EDIT:
                                    but
                                    QObject::connect(srcObject, SIGNAL(), destObject, SLOT(), Qt::DirectConnection) will run SLOT() in thread from which signal has been emitted.

                                    SPlattenS Offline
                                    SPlattenS Offline
                                    SPlatten
                                    wrote on last edited by
                                    #28

                                    @KroMignon Thank you, rapidly learning this.

                                    Kind Regards,
                                    Sy

                                    KroMignonK 1 Reply Last reply
                                    0
                                    • SPlattenS SPlatten

                                      @KroMignon Thank you, rapidly learning this.

                                      KroMignonK Offline
                                      KroMignonK Offline
                                      KroMignon
                                      wrote on last edited by KroMignon
                                      #29

                                      @SPlatten said in QTcpSocket client, write problem...:

                                      Thank you, rapidly learning this.

                                      Other things you should take care off when you are doing multithreading, is to set parent for class member to ensure that when you are moving the class instance to another thread, all member will follow.

                                      To better explain what I mean, suppose following example:

                                      class TestClass : public QObject
                                      {
                                          Q_OBJECT
                                      public:
                                          explicit TestClass(const QHostAddress &address, quint16 portNum, QHostAddress QObject * parent=nullptr)
                                               : QObject(parent), mSocket(new QTcpSocket(this))
                                         {
                                         }
                                      private:
                                          QTcpSocket* mSocket;
                                      };
                                      
                                      class TestClass2 : public QObject
                                      {
                                          Q_OBJECT
                                      public:
                                          explicit TestClass2(const QHostAddress &address, quint16 portNum, QHostAddress QObject * parent=nullptr)
                                               : QObject(parent), mSocket(new QTcpSocket())
                                         {
                                         }
                                      private:
                                          QTcpSocket* mSocket;
                                      };
                                      
                                      

                                      And somewhere in code:

                                      auto sock = new TestClass(QHostAddess::LocalHost, 888);
                                      auto sock2 = new TestClass2(QHostAddess::LocalHost, 889);
                                      auto t = new QThread();
                                      sock->moveToThread(t);
                                      sock2->moveToThread(t);
                                      t->start();
                                      

                                      now:

                                      • sock and sock->mSocket are moved to thread t.
                                      • sock2 is move the thead t but sock2->mSocket still lives in thread in which it have been created

                                      It is an old maxim of mine that when you have excluded the impossible, whatever remains, however improbable, must be the truth. (Sherlock Holmes)

                                      1 Reply Last reply
                                      1
                                      • SPlattenS Offline
                                        SPlattenS Offline
                                        SPlatten
                                        wrote on last edited by
                                        #30

                                        I feel like I am going around and round in circles and just not progressing. I have one process which listens for data on port 8123. It also starts another process which connects to the first process on the host IP and port 8123.

                                        The processes connect without problem, I am trying to write data from the second process to the first. I emit a signal from the socket that is used to connectToHost on the first process, I have a slot that connects to the emitted write signal:

                                        void clsMsgSender::onWrite(QJsonObject objJSON) {    
                                            if ( mpsckClient == nullptr ) {
                                                return;
                                            }
                                            QAbstractSocket::SocketState sckState = eGetSockState();
                                        
                                            if ( sckState != QAbstractSocket::ConnectedState ) {
                                        #if defined(DEBUG_SOCKETS)
                                                qdbg() << "Not connected!";
                                        #endif
                                                return;
                                            }
                                            QMutexLocker lock(&mMutex);
                                        #if defined(DEBUG_SOCKETS)
                                            QString strMsg(QJsonDocument(objJSON).toJson(QJsonDocument::Compact));
                                            qdbg() << QString("clsMsgSender::onWrite, to: %1:%2, data: %3")
                                                        .arg(mpsckClient->peerAddress().toString(), QString::number(mpsckClient->peerPort()), strMsg);
                                        #endif
                                            clsJSON::addCommonJSONflds(objJSON, nullptr, mpModule);
                                            //Insert a unique message ID into the message
                                            objJSON.insert(clsJSON::mscszMsgID, QString::number(clsMsgSender::ulnglngGetUniqueMsgID()));
                                            //Associate this TCP socket with the output data stream
                                            QByteArray arybytMsg;
                                            arybytMsg = QJsonDocument(objJSON).toJson(QJsonDocument::Compact);
                                            //Write message
                                            qint64 int64Written = mpsckClient->write(arybytMsg);
                                        #if defined(DEBUG_SOCKETS)
                                            qdbg() << QString("clsMsgSender::onWrite, written:%1")
                                                        .arg(int64Written);
                                        #endif
                                            if ( int64Written > 0 ) {
                                            //Remove the item from the queue
                                                mqueMsgsOut.dequeue();
                                            }
                                            //No longer busy
                                            mblnBusy = false;
                                        }
                                        

                                        When I emit the write signal I take a JSON packet from a queue, the item is only removed from the queue when the write completes. I can see using the Qt Creator debugger that in the onWrite slot the socket write is successful and returns the number of bytes written. However I see no evidence that the first application is receiving the data. What could be the cause?

                                        Kind Regards,
                                        Sy

                                        KroMignonK 1 Reply Last reply
                                        0
                                        • SPlattenS SPlatten

                                          I feel like I am going around and round in circles and just not progressing. I have one process which listens for data on port 8123. It also starts another process which connects to the first process on the host IP and port 8123.

                                          The processes connect without problem, I am trying to write data from the second process to the first. I emit a signal from the socket that is used to connectToHost on the first process, I have a slot that connects to the emitted write signal:

                                          void clsMsgSender::onWrite(QJsonObject objJSON) {    
                                              if ( mpsckClient == nullptr ) {
                                                  return;
                                              }
                                              QAbstractSocket::SocketState sckState = eGetSockState();
                                          
                                              if ( sckState != QAbstractSocket::ConnectedState ) {
                                          #if defined(DEBUG_SOCKETS)
                                                  qdbg() << "Not connected!";
                                          #endif
                                                  return;
                                              }
                                              QMutexLocker lock(&mMutex);
                                          #if defined(DEBUG_SOCKETS)
                                              QString strMsg(QJsonDocument(objJSON).toJson(QJsonDocument::Compact));
                                              qdbg() << QString("clsMsgSender::onWrite, to: %1:%2, data: %3")
                                                          .arg(mpsckClient->peerAddress().toString(), QString::number(mpsckClient->peerPort()), strMsg);
                                          #endif
                                              clsJSON::addCommonJSONflds(objJSON, nullptr, mpModule);
                                              //Insert a unique message ID into the message
                                              objJSON.insert(clsJSON::mscszMsgID, QString::number(clsMsgSender::ulnglngGetUniqueMsgID()));
                                              //Associate this TCP socket with the output data stream
                                              QByteArray arybytMsg;
                                              arybytMsg = QJsonDocument(objJSON).toJson(QJsonDocument::Compact);
                                              //Write message
                                              qint64 int64Written = mpsckClient->write(arybytMsg);
                                          #if defined(DEBUG_SOCKETS)
                                              qdbg() << QString("clsMsgSender::onWrite, written:%1")
                                                          .arg(int64Written);
                                          #endif
                                              if ( int64Written > 0 ) {
                                              //Remove the item from the queue
                                                  mqueMsgsOut.dequeue();
                                              }
                                              //No longer busy
                                              mblnBusy = false;
                                          }
                                          

                                          When I emit the write signal I take a JSON packet from a queue, the item is only removed from the queue when the write completes. I can see using the Qt Creator debugger that in the onWrite slot the socket write is successful and returns the number of bytes written. However I see no evidence that the first application is receiving the data. What could be the cause?

                                          KroMignonK Offline
                                          KroMignonK Offline
                                          KroMignon
                                          wrote on last edited by
                                          #31

                                          @SPlatten said in QTcpSocket client, write problem...:

                                          However I see no evidence that the first application is receiving the data. What could be the cause?

                                          TCP sockets are stream interfaces, and they use buffers (reception/transmission) to avoid sending too much small packets.
                                          To force data transfer you could do:

                                          // write to transmission buffer
                                          qint64 int64Written = mpsckClient->write(arybytMsg);
                                          // force transmission
                                          mpsckClient->flush();
                                          

                                          It is an old maxim of mine that when you have excluded the impossible, whatever remains, however improbable, must be the truth. (Sherlock Holmes)

                                          SPlattenS 1 Reply Last reply
                                          1

                                          • Login

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