problem with QLocalSocket sending continues data to QLocalServer
-
I'm trying to send some data from QLocalSocket to QLocalSever in a loop. Sever only gets the first data and not receiving subsequent data, but if I introduce 1 mec delay between each call from the client then the server starts to receive everything. Please check out the below Client & Server code.
client.cpp
#include "client.h" #include "QDataStream" #include <QTest> TestClient::TestClient() : m_socket{new QLocalSocket(this)}{ m_socket->connectToServer("TestServer"); if (m_socket->waitForConnected(1000)) { qDebug("socket Connected!"); } connect(m_socket, &QLocalSocket::readyRead, this, &TestClient::onNewData); } void TestClient::onNewData() { qCritical() << "data received from server"; } void TestClient::sendDataToServer() { QByteArray block; QDataStream out(&block, QIODevice::WriteOnly); out.setVersion(QDataStream::Qt_5_10); QString testString = "test data"; out << quint32(testString.size()); out << testString; m_socket->write(block); m_socket->flush(); } void TestClient::startClient() { for(int i = 0; i < 5; i++) { //QTest::qWait(1); //works if I uncomment this line sendDataToServer(); } }
server.cpp
#include "server.h" TestServer::TestServer() : m_server{new QLocalServer(this)} { QLocalServer::removeServer("TestServer"); if (!m_server->listen("TestServer")) { qCritical() << "couldn't connect to server"; } connect(m_server, &QLocalServer::newConnection, this, &TestServer::onNewConnection); } void TestServer::onNewConnection() { m_socket = m_server->nextPendingConnection(); connect(m_socket, &QLocalSocket::readyRead, this, &TestServer::onNewData); connect(m_socket, &QLocalSocket::disconnected, m_socket, &QLocalSocket::deleteLater); } void TestServer::onNewData() { QLocalSocket* client = qobject_cast<QLocalSocket*>(sender()); client->readAll(); qCritical() << "data read by server"; }
from the qt doc, it's stated that
readyRead() is not emitted recursively; if you reenter the event loop or call waitForReadyRead() inside a slot connected to the readyRead() signal, the signal will not be reemitted (although waitForReadyRead() may still return true).
so is this my problem? adding timer is the only solution here?
You can compile this test project -> testsocket
-
All is fine - you get all data with one readyRead signal / readAll() call.
-
@Venkateswaran said in problem with QLocalSocket sending continues data to QLocalServer:
Sever only gets the first data and not receiving subsequent data,
How are you sure? You do not debug out the content/length of
client->readAll();
, so you don't know. My guess is: you assume areadAll()
oronNewData
signal correspond one-to-one withwrite
/flish
from client. But they don't. Your "1 msec delay" will make that true, probably, which is why you think you need that. You don't. -
Christian Ehrlicher Lifetime Qt Championreplied to Venkateswaran on last edited by Christian Ehrlicher
@Venkateswaran Why? It's a stream with no further protocol. It can even happen that you get a readyRead signal for every single byte you sent.
-
@Venkateswaran
And it absolutely is not! :)readyRead
fires when there is at least 1 byte available.readAll
reads all that happens to be there when it is called. Anything ranging from 0 bytes to every byte sent!readyRead
won't fire again till you've done areadAll
.
That's it. No one-to-one. Your job to buffer received data at receiver, or split it up, if that's what you want to do.
-
@JonB Thanks for clarifying this. Now I have another problem, on the server-side, I need to call another function with received test string from the client. I have tested the readAll() and as you said I'm receiving 130 bytes all at once (which is 5 times my test string). So how do I separate on server-side? I'm using QDataStream on client-side to send data and is there an elegant way to decouple the received bytes at server-side with QDataStream? maybe its a really basic question but it would be helpful for me if you show some example.
-
@Venkateswaran
Start by: have you read (and understood!) all the detail in https://doc.qt.io/qt-5/qdatastream.html#details ? And do look at subsection https://doc.qt.io/qt-5/qdatastream.html#using-read-transactions, because you may be looking for that.How is the client sending? ("I'm using QDataStream on client-side to send data" --- with just which calls on what data object types?) If you are using
QDataStream
at client send you will wantQDataStream
at server receive. And just btw: when you talk sometimes about "bytes" and sometimes about "string" do you indeed wantQDataStream
or did you maybe wantQTextStream
? -
@Venkateswaran
Nope :) Not unless you want to, it just stops client proceeding to the next line of code till bytes are written. But it makes no difference to the protocol/behaviour. And no effect at server-side. -
@JonB Thanks for the information. I want to send Boolean, Number, String from the client so DataStream would be the right one.
This is how I'm sending data from the client :void TestClient::sendDataToServer() { QByteArray block; QDataStream out(&block, QIODevice::WriteOnly); out.setVersion(QDataStream::Qt_5_10); QString testString = "test data"; out << quint32(testString.size()); out << testString; m_socket->write(block); m_socket->flush(); }
This is what I tried at the server side to receive data (and it work for this basic example).
void TestServer::onNewData() { QLocalSocket* client = qobject_cast<QLocalSocket*>(sender()); qCritical() << "TestServer::onNewData" << client->bytesAvailable(); QDataStream in; in.setDevice(client); in.setVersion(QDataStream::Qt_5_10); quint32 blockSize = 0; QString test; while(client->bytesAvailable() > (int)sizeof(quint32)) { in >> blockSize; if (client->bytesAvailable() < blockSize || in.atEnd()) return; in >> test; qDebug() << test << "printing received value"; } qCritical() << "data read by server"; }
But looks like This Answer has a nice example to start with
-
@Venkateswaran
Note that the link you reference (by @VRonin) uses the transactions I suggested earlier: https://doc.qt.io/qt-5/qdatastream.html#using-read-transactions. NobytesAvailable()
or buffering. Up to you. -
@JonB said in problem with QLocalSocket sending continues data to QLocalServer:
readyRead won't fire again till you've done a readAll.
This is not correct. From https://doc.qt.io/qt-5/qabstractsocket.html
The
readyRead()
signal is emitted every time a new chunk of data has arrived.So it doesn't care whether you read the data or not
I suggest having a look at this article it uses
QTcpSocket
but the code is exactly the same forQLocalSocket
. I'd focus on theChatClient::onReadyRead
method and its explanation below -
@VRonin said in problem with QLocalSocket sending continues data to QLocalServer:
This is not correct.
Damn, and sorry! I thought that it had said that, but not. I may have confused with
readyRead() is not emitted recursively; if you reenter the event loop or call waitForReadyRead() inside a slot connected to the readyRead() signal, the signal will not be reemitted (although waitForReadyRead() may still return true).