QTcpServer / QTcpSocket help
-
I'm writing and application that uses QTcpServer and another that uses QTcpSocket. The server application inherits from QTcpServer:
class clsSocketServer : public QTcpServer { Q_OBJECT protected: void incomingConnection(qintptr sfd); public: static const QString mscstrCRLF; static const quint16 mscuint16port; explicit clsSocketServer(QObject* pParent = nullptr); ~clsSocketServer(); public slots: void discardClient(); void readClient(); };
Implementation:
const QString clsSocketServer::mscstrCRLF("\r\n"); const quint16 clsSocketServer::mscuint16port = 8123; /** * @brief clsSocketServer::clsSocketServer - class constructor */ clsSocketServer::clsSocketServer(QObject* pParent) : QTcpServer(pParent) { QString strListenFailure = QString("Cannot listen to port: ") + QString::number(clsSocketServer::mscuint16port); Q_ASSERT_X(listen(QHostAddress::Any, clsSocketServer::mscuint16port)!=false ,"clsSocketServer::clsSocketServer", strListenFailure.toLatin1().data()); } /** * @brief clsSocketServer::~clsSocketServer - class destructor */ clsSocketServer::~clsSocketServer() { close(); } /** * @brief clsSocketServer::discardClient */ void clsSocketServer::discardClient() { QTcpSocket* pSckClient = (QTcpSocket*)sender(); pSckClient->deleteLater(); } /** * @brief clsSocketService::incomingConnection * @param sfd : Client Socket Descriptor */ void clsSocketServer::incomingConnection(qintptr sfd) { QTcpSocket* pSckClient = new QTcpSocket(this); connect(pSckClient, SIGNAL(readyRead()), this, SLOT(readClient())); connect(pSckClient, SIGNAL(disconnected()), this, SLOT(discardClient())); pSckClient->setSocketDescriptor(sfd); } /** * @brief clsSocketServer::readClient */ void clsSocketServer::readClient() { enum { REQ_METHOD = 0 ,REQ_DATA }; QTcpSocket* pSckClient = (QTcpSocket*)sender(); if (!pSckClient->canReadLine() ) { //Cannot read input stream, abort! return; } QStringList slstTokens = QString(pSckClient->readLine()).split(QRegExp("[ \r\n][ \r\n]*")); ... }
My application launches a child process which uses QTcpSocket:
//Set-up the data stream mdsIn.setDevice(this); mdsIn.setVersion(QDataStream::Qt_5_15); //Connect up the signals connect(this, &QIODevice::readyRead, this, &clsModHelper::dataIn); connect(this, &QAbstractSocket::errorOccurred, this, &clsModHelper::errorOccurred); //Connect to the Application connectToHost(clsModHelper::mscpszHost, muint16Port); if ( !waitForConnected(clsModHelper::mscintConnectionTimeout) ) { exit(EXIT_FAILURE); }
clsModHelper::mscpszHost is "localhost" and muint16Port is 8123. The slots for dataIn and errorOccurred:
/** * @brief clsModHelper::dataIn */ void clsModHelper::dataIn() { qdbg() << "dataIn"; } /** * @brief clsModHelper::errorOccurred * @param socketError : Error information */ void clsModHelper::errorOccurred(QAbstractSocket::SocketError socketError) { qdbg() << "errorOccurred: " << errorString(); }
I'm not seeing anything in either dataIn or errorOccurred. I also tried adding:
pSckClient->write("Hello", 5);
To the end of the incomingConnection function in the main application, I don't see it received by the child process. What have I done wrong or missed out?
-
@SPlatten said in QTcpServer / QTcpSocket help:
First, this is not a good practice:
Q_ASSERT_X(listen(QHostAddress::Any, clsSocketServer::mscuint16port)!=false
,"clsSocketServer::clsSocketServer", strListenFailure.toLatin1().data());When build as release, this will be removed!
Please change this into:bool success = listen(QHostAddress::Any, clsSocketServer::mscuint16port); Q_ASSERT_X(!success,"clsSocketServer::clsSocketServer", strListenFailure.toLatin1().data());
or
listen(QHostAddress::Any, clsSocketServer::mscuint16port); Q_ASSERT_X(!isListening(),"clsSocketServer::clsSocketServer", strListenFailure.toLatin1().data());
-
@SPlatten And second, where did you connect
QTcpServer::newConnection
?I am missing something like:
clsSocketServer::clsSocketServer(QObject* pParent) : QTcpServer(pParent) { connect(this, &QTcpServer::newConnection, [this](){ while(hasPendingConnections()) { auto socket = m_server->nextPendingConnection(); if(!socket) break; // do something with the client! } }); bool success = listen(QHostAddress::Any, clsSocketServer::mscuint16port); Q_ASSERT_X(!success,"clsSocketServer::clsSocketServer", strListenFailure.toLatin1().data()); }
-
@KroMignon, I used:
https://doc.qt.io/qt-5/qtnetwork-threadedfortuneserver-example.htmlAs a guide for the server, I don't see anything like that on that page?
-
@KroMignon said in QTcpServer / QTcpSocket help:
And second, where did you connect QTcpServer::newConnection?
He's overwriting QTcpServer::incomingConnection() because he follows the threading example (for unknown reasons)
-
@Christian-Ehrlicher , is it wrong?
-
@SPlatten said in QTcpServer / QTcpSocket help:
Are you sure your test in Q_ASSERT_X is correct?
my bad, sorry: the test is inverted!
should beQ_ASSERT_X(success,"clsSocketServer::clsSocketServer", strListenFailure.toLatin1().data()); or Q_ASSERT_X(isListening(),"clsSocketServer::clsSocketServer", strListenFailure.toLatin1().data());
-
@SPlatten said in QTcpServer / QTcpSocket help:
is it wrong?
It is not specially wrong, but using
QTcpServer::waitForConnected()
is a blocking method, so no event will be handled during this call for the used thread!Using
QTcpServer::newConnection()
signal is the non blocking alternative, which is more QEventLoop/QEvent friendly ;)==> Read documentation for more details
-
@KroMignon, I call connectToHost in the process that is launched this connects to the application that launched it and this uses QTcpSocket not QTcpServer. The new connection would be created by the launcher when it processes the connection.
I call waitForConnection purposely as the child process has no other purpose without a connection to the launcher.
I think the problem is in the launcher in this function:
void clsSocketServer::incomingConnection(qintptr sfd) { QTcpSocket* pSckClient = new QTcpSocket(this); connect(pSckClient, SIGNAL(readyRead()), this, SLOT(readClient())); connect(pSckClient, SIGNAL(disconnected()), this, SLOT(discardClient())); pSckClient->setSocketDescriptor(sfd); pSckClient->write("Hello", 5); }
I can see in the debugger an incomingConnection is called, but the test write, doesn't happen.
-
@KroMignon said in QTcpServer / QTcpSocket help:
Please change this into:
bool success = listen(QHostAddress::Any, clsSocketServer::mscuint16port);
Q_ASSERT_X(!success,"clsSocketServer::clsSocketServer", strListenFailure.toLatin1().data());or
listen(QHostAddress::Any, clsSocketServer::mscuint16port);
Q_ASSERT_X(!isListening(),"clsSocketServer::clsSocketServer", strListenFailure.toLatin1().data());You can use
Q_ASSUME
is for this kind of cases.Q_ASSUME(listen(QHostAddress::Any, clsSocketServer::mscuint16port));
@SPlatten said in QTcpServer / QTcpSocket help:
I used:
https://doc.qt.io/qt-5/qtnetwork-threadedfortuneserver-example.htmlUnfortunately that's not a good example to start on TCP. Some of us here prepared a better example to serve as a starting point, have a look at https://wiki.qt.io/WIP-How_to_create_a_simple_chat_application