Unsolved QTcpSocket client, write problem...
-
@SPlatten Start without debugger
-
@jsulm , how is that going to help? I ran it in the debugger because no data is being written, so I'm trying to determine why it isn't writing.
-
As I said in my previous post, those entires are grayed and when I click on those there is no data, no source it stops in assembler.
Ah, I understand.
So far as I know, all of these messages go via the qInstallMessageHandler(QtMessageHandler handler). In a complex program it is vital you use this to install your own message handler for all messages, including those issued in Qt's own code. Then you can see the message text, or break there in the debugger and look at variables.
Have you done this for your application?
[BTW: When you say you see no message now, you are checking in the appropriate tab of the debugger? Anyway, always install your own handler, so you can break etc. there.]
-
@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
-
@SPlatten
The fact thatQMessageLogger::warning
is callingabort()
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 fromQSocketNotifier::setEnabled()
. -
@JonB , I think you posted before I edited, see the end of the last post.
-
@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 :)
-
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
-
@J-Hilk , thank you, I've removed the Qt::DirectConnection parameter from the connects and now the warning has gone.
-
@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
-
@SPlatten
A while back in another of your post threads you were using explicitQt::DirectConnection
s, 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 yourconnect()s
, I just don't get it, it keeps leading to this kind of problem? -
@JonB , they are gone now.
-
@J-Hilk , I do register the type.
-
@SPlatten said in QTcpSocket client, write problem...:
@JonB , they are gone now.
:) May I suggest you never put them in? The default for
connect()
isDirectConnection
, and Qt only changes that toQueued
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 thatqDebugMsgHandler()
is lean & clean. And wrap that with atry
handler. If it goes doolally, allow the originalqDebugMsgHandler()
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. -
@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.
-
@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 callingabort()
does not look right.He's running with fatal warnings (as suggested in earlier threads), so it's exactly right!
-
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);
-
@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 threadAs 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 sureqint64 int64Written = mpsckClient->write(arybytMsg);
is done in the right thread (mpsckClient->thread() == QThread::currentThread()
). -
@KroMignon I thought that one of the benefits of using signals and slots is that you can be assured that they are thread safe?
-
@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 ensureSLOT()
will run indestObject
work thread, when signal is emitted.EDIT:
but
QObject::connect(srcObject, SIGNAL(), destObject, SLOT(), Qt::DirectConnection)
will runSLOT()
in thread from which signal has been emitted.