Writing to QTcpSocket does not always emit readyRead signal on opposite QTcpSocket - c++

I have been stuck on this for the past 5 days, I have no idea how to proceed.
Overview:
I have a client UI which interacts with a data handler library, and the data handler library utilizes a network manager library, which is where my problem lies.
More Info
Firstly, QT provides a basic example for interactions between a QTcpServer (Fortune Server)and a QTcpSocket (Fortune Client).
I thus implemented this code into an extremely basic example of my own, which works like a charm and has no issues.
My own adaption of fortune client and server for the record (basic)
Quick Explaination:
Server application runs, click on start server, then on the client side, enter text in field and click connect to server and text is displayed, easy!
Problem:
Implementing the code above into my network manager library, does not fire the QTcpSocket::readyRead() in the server application above.
It connects to the server, where the QTcpServer::newConnection() is fired, as expected, straight after which the client writes to the socket but the readyRead() on the server socket does not fire, however in the example given it does.
Note:
The same port and ip address is used in this server-client application example and my current application, and the server is also running.
Further Information:
From the above code, I copied over directly from the client. Only 2 things were changed/modified:
String that is sent to server
return types for method
This was copied into my network mannager ::write() method. When running my application, and instance of QMainWindow is passed via data handler class and creates an instance of my network manager class which inherits QObject and implements the Q_OBJECT macro.
Code Examples:
//client_UI Class (snippet):
data_mananger *dman = new data_mananger(this); //this -> QMainWindow
ReturnObject r = dman->NET_AuthenticateUser_GetToken(Query);
//data_manager library (snippet)
data_mananger::data_mananger(QObject *_parent) :
parent(_parent)
{}
ReturnObject data_mananger::NET_AuthenticateUser_GetToken(QString Query){
//Query like "AUTH;U=xyz#a;P=1234"
//convert query string to char
QByteArray ba = Query.toLatin1();
//send query and get QList return
ReturnCode rCode = networkManager.write(ba);
//...
}
//netman library (snippet)
//.h
class NETMANSHARED_EXPORT netman : public QObject
{
Q_OBJECT
public
netman();
netman(QObject *_parent);
//...
private:
QTcpSocket *tcp_con;
//...
};
//cpp
netman::netman(QObject *_parent) :
parent(_parent)
{
tcp_con = new QTcpSocket(parent);
}
return;
}
serverIP.setAddress(serverInfo.addresses().first().toIPv4Address());
}
ReturnCode netman::write(QByteArray message, int portNumber){
tcp_con->connectToHost(QHostAddress("127.0.0.1"), 5000);
if (!tcp_con->waitForConnected())
{
qDebug(log_lib_netman_err) << "Unable to connect to server";
return ReturnCode::FailedConnecting;
}
if (!tcp_con->isValid()) {
qDebug(log_lib_netman_err) << "tcp socket invalid";
return ReturnCode::SocketError;
}
if (!tcp_con->isOpen()) {
qDebug(log_lib_netman_err) << "tcp socket not open";
return ReturnCode::SocketError;
}
// QByteArray block(message);
QByteArray block;
QDataStream out(&block,QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_4_0);
out << QString("Hello world");
if (!tcp_con->write(block)){
qDebug(log_lib_netman_err) << "Unable to send data to server";
return ReturnCode::WriteFailed;
}
else{
qDebug(log_lib_netman_info) << "Data block sent";
return ReturnCode::SentSuccess;
}
}
Conclusion:
The core code of the client side has been fully implemented, yet I cannot see why this error occurs.
I would very much appreciate help/advice!

Add a tcp_con->flush() statement to the end of your write function.
Why/how this works
You weren't getting a readyRead signal in your receiver because the written data was being buffered into the socket but not actually transmitted 'over the wire'. The flush() command causes the buffer to be transmitted. From the docs
This function writes as much as possible from the internal write
buffer to the underlying network socket, without blocking. If any data
was written, this function returns true; otherwise false is returned.
How are you supposed to know
In my case a lot of experience/frustration with serial ports and flushing. It's the equivalent of "have you rebooted it?" in the socket debugging toolbox.
If everything else is working fine, you may not have to flush, but it's kind of application specific and depends on the lifetime of the socket, the TCP window size, socket option settings, and various other factors. That said, I always flush because I like having complete control over my sockets, and I want to make sure data is transmitted when I want it to be. I don't think it's a hack, but in some cases it could be indicative of some other problem. Again, application specific.
Why might the buffer not be flushing itself?
I'm pretty sure no flush is needed in the fortune server example because they disconnectFromHost at the end of the sendFortune() function, and from the Qt documentation:
Attempts to close the socket. If there is pending data waiting to be
written, QAbstractSocket will enter ClosingState and wait until all
data has been written.
The socket would disconnect if it were destroyed as well, but from what I can see of your code you aren't doing that either, and the buffer isn't full, so probably nothing is actually stimulating the buffer to flush itself.
Other causes can be:
flow control isn't returned to the event loop (blocking calls, etc), so the buffer flush is never performed.
Transmit is occuring inside of a loop, which seems like it will exit (e.g. while(dataToTransmit)), but in fact the condition never becomes false, which leads to the event loop being blocked.
Nagles algorithm: the buffer may be waiting for more data before it flushes itself to keep network throughput high. You can disable this by setting the QAbstractSocket::LowDelayOption, but it may adversely affect your throughput... it's normally used for latency-sensative applications.

Related

Worker threads with shared resources in Qt application

I am working on a Qt application which involves serial communication with one or multiple devices. There are different procedures that can be executed simulteanously and each procedure may send one or unknown number of commands to a device and may receive data in response. To make it more clear, here is a graphical illustration of the scenario:
Clicking on a button triggers the execution of the corresponding procedure. So two or more different procedures may be running at the same time when the user clicks on two or more buttons in a short interval. Actually the only thing that may be shared between them is the serial communication with a single device; otherwise they are mostly independent of one another. And here are two pseudo-code examples of what a procedure may look like:
Procedure A:
begin
write command a1 on serial port
wait for one second
perform some computations
write command a2 on serial port
wait for one second
end
Procedure B:
begin
while true:
write command b1 on serial port
read the response from serial port
perform some computations
if a condition holds return, otherwise continue
end
My solution and its issue:
To simplify the situation consider that there is only one device which we need to communicate with. Since procedures can be executed simulteanously (and only one of them can communicate with the device through serial port at a time) I have created one thread and one worker class for each of the procedures and have moved the workers to their corresponding threads. To synchronize procedures when accessing the serial port I have created one mutex:
MainWindow.h
class MainWindow : public QMainWindow {
public:
//...
QSerialPort* serial_;
QMutex serial_mutex_;
private:
//...
ProcAWorker* proca_worker;
ProcBWorker* procb_worker;
ProcCWorker* procc_worker;
ProcDWorker* procd_worker;
QThread proca_thread;
QThread procb_thread;
QThread procc_thread;
QThread procd_thread;
}
MainWindow.cpp
void MainWindow::onConnectButtonClicked()
{
serial_ = new QSerialPort();
// configure serial port settings
serial_->open(QIODevice::ReadWrite);
}
void MainWindow::onButtonAClicked()
{
proca_worker = new ProcAWorker(0, this); // pass a pointer to this class to be able to access its methods and members
proca_worker->moveToThread(&proca_thread);
// setup worker-thread connections: started, quit, finished, etc.
proca_thread.start(); // triggers `proccess` slot in proca_worker
}
// same thing for other buttons and procedures
ProcAWorker.cpp
void ProcAWorker::ProcAWorker(QObject *parent, QMainWindow *wnd) :
QObject(parent), wnd_(wnd)
{
}
void ProcAWorker::process()
{
wnd_->serial_mutex_->lock();
wnd_->serial_->write('Command a1'); // Warning occurs in this line
bool write_ok = client_->serial_->waitForBytesWritten(SERIAL_WRITE_TIMEOUT);
wnd_->serial_mutex_->unlock();
QThread::sleep(1);
// perform some computations
wnd_->serial_mutex_->lock();
wnd_->serial_->write('Command a2');
bool write_ok = client_->serial_->waitForBytesWritten(SERIAL_WRITE_TIMEOUT);
wnd_->serial_mutex_->unlock();
if (write_ok) {
// signal successful to main window
emit success();
}
}
However, when the write operation is performed on the serial port (i.e. wnd_->serial_->write('Command a1');) the following warning is shown:
QObject: Cannot create children for a parent that is in a different
thread. (Parent is QSerialPort(0x18907d0), parent's thread is
QThread(0x13cbc50), current thread is QThread(0x17d8d08)
My questions:
1) I have already looked at other questions on Stackoverflow regarding this warning, but their answers have only mentioned that signal/slot should be used. I am familiar with using signal/slot to communicate with worker threads. However, I can't figure out how to implement my specific scenario (simultaneous running procedures with shared resources like serial port) using signal/slot or how can I modify my current solution to resolve this issue? Note that the procedures should be allowed to run in parallel (unless in those moments when they want to communicate with the device). Obviously one can run the procedures sequentially (i.e. one after another) but I am not looking for such solutions.
2) Actually there is also a "Halt" button that stops all the running procedures and sends a halt command to the device. But I could not figure out to implement this functionality as well (set a flag, send a quit signal, etc.). Could you please give me some hints in this regards as well?
First of all, you don't need explicit multithreading (it's optional), second of all you don't need any manually managed synchronization primitives.
Then, model each procedure using a state machine. Hopefully the communication protocol allows each procedure recognize the responses to its own commands, so that even though you'd be replicating the incoming data to all of the procedures, they'd ignore the data irrelevant to them.
This answer has a sketch of a solution that does exactly what you want, sans multiplexing. Multiplexing a QIODevice is trivial when you expose it via local pipes: everything incoming from the port is written to one end of one or more local pipes. Everything incoming from the pipes is written to the port. The pipes will maintain the integrity of the packets as long as you open their procedure end in Unbuffered mode. That way each write will arrive at the serial port as a contiguous block of bytes, and will be written to the port in the same manner.
How would you multiplex? Like so:
class IODeviceMux : public QObject {
Q_OBJECT
QVector<QPointer<AppPipe>> m_portPipes;
QVector<QPointer<AppPipe>> m_userPipes;
QPointer<QSerialPort> m_port;
public:
IODeviceMux(QObject *parent = {}) : QObject(parent) {}
void setPort(QIODevice *port) {
if (m_port) {
disconnect(m_port.get(), 0, this, 0);
m_userPipes.removeAll({});
for (auto pipe : qAsConst(m_userPipes))
disconnect(m_port.get(), 0, pipe.get(), 0);
}
m_port = port;
connect(m_port.get(), &QIODevice::readyRead, this, &IODeviceMux::onPortRead);
}
AppPipe *getPipe() {
QScopedPointer<AppPipe> user(new AppPipe(QIODevice::ReadWrite | QIODevice::Unbuffered));
auto *port = new AppPipe(QIODevice::ReadWrite | QIODevice::Unbuffered, this);
user->addOther(port);
connect(port, &QIODevice::readyRead, this, &IODeviceMux::onPipeRead);
connect(m_port.get(), &QIODevice::bytesWritten, user.get(), &QIODevice::bytesWritten);
connect(user, &QObject::destroyed, port, &QObject::deleteLater);
m_userPipes.push_back(user.get());
m_portPipes.push_back(port);
return user.take();
}
private:
void onPortRead() {
if (!m_port) return;
auto data = m_port->readAll();
m_portPipes.removeAll({});
for (auto pipe : qAsConst(m_portPipes))
pipe->write(data);
}
void onPipeRead() {
auto *pipe = qobject_cast<AppPipe*>(sender());
QByteArray data;
if (pipe) data = pipe->readAll();
if (m_port) m_port->write(data);
}
};
The procedures would each getPipe() and treat the pipe as if it was a serial port device. Each write into a pipe gets faithfully executed on the port. Each readyRead on the port is faithfully forwarded, with same data amounts available immediately to read. Even the port's bytesWritten is forwarded. But bytesToWrite doesn't work - it always returns zero. This could be fixed by adding an option to AppPipe to query this value.
That's about all you need to get it to work, I'd think.

QTcpSocket to QTcpSocket in same object

I am attempting to fake a transfer between two QTcpSockets that happen to be in the same class (which is a googletest fixture). The focus of this is to see if I can send multiple messages between the two and properly extract them again. However, it seems that the two sockets won't connect. Most of the posts I've seen that relate to this don't come up with a working answer, and being as this is definitely not the intended means of use, I'm not sure that there is a simple one.
What I have for setting up the connection:
class TTest : public ::testing::Test, public QObject
{
//Q_OBJECT
protected:
QTcpServer qserv;
QTcpSocket qtcpsock1; //send
QTcpSocket *qtcpsock2; //rcv
TTest() : qserv(this), qtcpsock1(this)
{
while (!qserv.isListening())
{
qserv.listen();
}
qtcpsock1.connectToHost(QHostAddress::LocalHost, qserv.serverPort());
qtcpsock2 = qserv.nextPendingConnection();
qtcpsock1.waitForConnected();
if (!qtcpsock2) std::cout << "socket 2 not initialized\n";
qserv.close();
}
}
Signals/slots currently not in use.
The problem with this is that the event polling loop of the application will not run, so no events will be handled and your function calls will simply not work without it.
In short, the waitForConnected() call will wait for an event that never happens.
The natural solution with Qt is of course to use signals and slots, and let the normal application event loop run.
On a slightly related note: If you want internal communication within the same process consider something other than (heavy and complex) TCP sockets. Simple message queues? Anonymous pipes? Plain strings or arrays?

Qt TCP client/server Chat Application. How to send a private message

I have a simple tcp client/server chat application that looks like this:
And here is my client source code:
#include "MainWindow.h"
// We'll need some regular expression magic in this code:
#include <QRegExp>
// This is our MainWindow constructor (you C++ n00b)
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
{
// When using Designer, you should always call setupUi(this)
// in your constructor. This creates and lays out all the widgets
// on the MainWindow that you setup in Designer.
setupUi(this);
// Make sure that we are showing the login page when we startup:
stackedWidget->setCurrentWidget(loginPage);
// Instantiate our socket (but don't actually connect to anything
// yet until the user clicks the loginButton:
socket = new QTcpSocket(this);
// This is how we tell Qt to call our readyRead() and connected()
// functions when the socket has text ready to be read, and is done
// connecting to the server (respectively):
connect(socket, SIGNAL(readyRead()), this, SLOT(readyRead()));
connect(socket, SIGNAL(connected()), this, SLOT(connected()));
}
// This gets called when the loginButton gets clicked:
// We didn't have to use connect() to set this up because
// Qt recognizes the name of this function and knows to set
// up the signal/slot connection for us.
void MainWindow::on_loginButton_clicked()
{
// Start connecting to the chat server (on port 4200).
// This returns immediately and then works on connecting
// to the server in the background. When it's done, we'll
// get a connected() function call (below). If it fails,
// we won't get any error message because we didn't connect()
// to the error() signal from this socket.
socket->connectToHost(serverLineEdit->text(), 4200);
}
// This gets called when the user clicks the sayButton (next to where
// they type text to send to the chat room):
void MainWindow::on_sayButton_clicked()
{
// What did they want to say (minus white space around the string):
QString message = sayLineEdit->text().trimmed();
// Only send the text to the chat server if it's not empty:
if(!message.isEmpty())
{
socket->write(QString(message + "\n").toUtf8());
}
// Clear out the input box so they can type something else:
sayLineEdit->clear();
// Put the focus back into the input box so they can type again:
sayLineEdit->setFocus();
}
// This function gets called whenever the chat server has sent us some text:
void MainWindow::readyRead()
{
// We'll loop over every (complete) line of text that the server has sent us:
while(socket->canReadLine())
{
// Here's the line the of text the server sent us (we use UTF-8 so
// that non-English speakers can chat in their native language)
QString line = QString::fromUtf8(socket->readLine()).trimmed();
// These two regular expressions describe the kinds of messages
// the server can send us:
// Normal messges look like this: "username:The message"
QRegExp messageRegex("^([^:]+):(.*)$");
// Any message that starts with "/users:" is the server sending us a
// list of users so we can show that list in our GUI:
QRegExp usersRegex("^/users:(.*)$");
// Is this a users message:
if(usersRegex.indexIn(line) != -1)
{
// If so, udpate our users list on the right:
QStringList users = usersRegex.cap(1).split(",");
userListWidget->clear();
foreach(QString user, users)
new QListWidgetItem(QPixmap(":/user.png"), user, userListWidget);
}
// Is this a normal chat message:
else if(messageRegex.indexIn(line) != -1)
{
// If so, append this message to our chat box:
QString user = messageRegex.cap(1);
QString message = messageRegex.cap(2);
roomTextEdit->append("<b>" + user + "</b>: " + message);
}
}
}
void MainWindow::onListWidgetItemClicked(const QModelIndex &index)
{
}
// This function gets called when our socket has successfully connected to the chat
// server. (see the connect() call in the MainWindow constructor).
void MainWindow::connected()
{
// Flip over to the chat page:
stackedWidget->setCurrentWidget(chatPage);
// And send our username to the chat server.
socket->write(QString("/me:" + userLineEdit->text() + "\n").toUtf8());
}
It works fine, but if one the users writes a message it appears on the textedit and everybody who is connected can see it. What I want to do is to be able to send a private message, to a particular user which I select from the users listwidget, something similar to Skype let's say.
For example if I'm user 1 and I select user 2 from the listwidget, I want to send him a message which user 3 won't be able to see.
I'm sorry for my bad english and for this stupid question but I can't figure out how to approach this problem. I would gladly accept any suggestions.
Judging by the implementation of on_sayButton_clicked and readyRead, your protocol only supports broadcast messages, as everything sent to the server is unconditionally sent to all currently connected users.
You will have to introduce a separate message type in the protocol in order to instruct the server to send the message only to the given user. It looks like you're distinguishing ordinary messages from control messages via testing for a specific token at the beginning of the string. If you want to take that further, you can specify private:username:message as the beginning of a packet that's supposed to be sent only to username. Then, the server can lookup the IP of the user with username, and send message only to its socket, probably with another extra token to identify that this is a private message, and not a one that's supposed to be displayed in the general chat window.
Keep in mind that your current implementation allows users to send server messages simply by entering appropriate strings in the input box. I would propose creating an entirely separate class that takes objects which represent messages on input, and sends them over a socket to the server. Analogously, it provides a signal with an object that represents the message when one is sent to the user. This way, you're abstracting away the serialization and deserialization of server messages from the GUI logic, and you can easily change the implementation of the client-server communication code without re-doing the GUI. If you decide to do this, you should re-use the same code between the server and the client, if possible : this will save you many headaches that may arise from the server and the client using different code for generating (or extracting) actual messages from the received packets.

How to make sure that readyRead() signals from QTcpSocket can't be missed?

When using QTcpSocket to receive data, the signal to use is readyRead(), which signals that new data is available.
However, when you are in the corresponding slot implementation to read the data, no additional readyRead() will be emitted.
This may make sense, as you are already in the function, where you are reading all the data that is available.
Problem description
However assume the following implementation of this slot:
void readSocketData()
{
datacounter += socket->readAll().length();
qDebug() << datacounter;
}
What if some data arrives after calling readAll() but before leaving the slot?
What if this was the last data packet sent by the other application (or at least the last one for some time)?
No additional signal will be emitted, so you have to make sure to read all the data yourself.
One way to minimize the problem (but not avoid it totally)
Of course we can modify the slot like this:
void readSocketData()
{
while(socket->bytesAvailable())
datacounter += socket->readAll().length();
qDebug() << datacounter;
}
However, we haven't solved the problem. It is still possible that data arrives just after the socket->bytesAvailable()-check (and even placing the/another check at the absolute end of the function doesn't solve this).
Making sure to be able to reproduce the problem
As this problem of course happens very rarely, I stick to the first implementation of the slot, and I'll even add a an artificial timeout, to be sure that the problem occurs:
void readSocketData()
{
datacounter += socket->readAll().length();
qDebug() << datacounter;
// wait, to make sure that some data arrived
QEventLoop loop;
QTimer::singleShot(1000, &loop, SLOT(quit()));
loop.exec();
}
I then let another application send 100,000 bytes of data.
This is what happens:
new connection!
32768 (or 16K or 48K)
The first part of the message is read, but the end isn't read anymore, as readyRead() won't be called again.
My question is: what is the best way to be sure, this problem never occurs?
Possible solution
One solution I came up with is calling the same slot again at the end again, and to check at the beginning of the slot, if there is any more data to read:
void readSocketData(bool selfCall) // default parameter selfCall=false in .h
{
if (selfCall && !socket->bytesAvailable())
return;
datacounter += socket->readAll().length();
qDebug() << datacounter;
QEventLoop loop;
QTimer::singleShot(1000, &loop, SLOT(quit()));
loop.exec();
QTimer::singleShot(0, this, SLOT(readSocketDataSelfCall()));
}
void readSocketDataSelfCall()
{
readSocketData(true);
}
As I don't call the slot directly, but use QTimer::singleShot(), I assume that the QTcpSocket can't know that I'm calling the slot again, so the problem that readyRead() isn't emitted can't happen anymore.
The reason why I have included the parameter bool selfCall is that the slot which is called by the QTcpSocket isn't allowed to exit sooner, else the same problem can occur again, that data arrives exactly at the wrong moment and readyRead() isn't emitted.
Is this really the best solution to solve my problem?
Is the existence of this problem a design error in Qt or am I missing something?
Short answer
The documentation of QIODevice::readyRead() states:
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.
Thus, make sure that you
don't instantiate a QEventLoop inside your slot,
don't call QApplication::processEvents() inside your slot,
don't call QIODevice::waitForReadyRead() inside your slot,
don't use the same QTcpSocket instance within different threads.
Now you should always receive all data sent by the other side.
Background
The readyRead() signal is emitted by QAbstractSocketPrivate::emitReadyRead() as follows:
// Only emit readyRead() when not recursing.
if (!emittedReadyRead && channel == currentReadChannel) {
QScopedValueRollback<bool> r(emittedReadyRead);
emittedReadyRead = true;
emit q->readyRead();
}
The emittedReadyRead variable is rolled back to false as soon as the if block goes out of scope (done by the QScopedValueRollback). So the only chance to miss a readyRead() signal is when the control flow reaches the if condition again before the processing of the last readyRead() signal has finished (in other words, when there would be a recursion).
And a recursion should only be possible in the situations listed above.
I think scenario mentioned in this topic has two major cases which works differently, but in general QT doesn't have this problem at all and I will try to explain below why.
First case: Single threaded application.
Qt uses select() system call to poll open file descriptor for any change happened or operations available. Simple saying on every loop Qt checks if any of opened file descriptors have data available to read/closed etc. So on single threaded application flow looks like that (code part simplified)
int mainLoop(...) {
select(...);
foreach( descriptor which has new data available ) {
find appropriate handler
emit readyRead;
}
}
void slotReadyRead() {
some code;
}
So what will happend if new data arrived while program still inside slotReadyRead.. honestly nothing special. OS will buffer data, and as soon as control will return to next execute of select() OS will notify software that there are data available for particular file handle. It works in absolutely the same way for TCP sockets/files etc.
I can imaging situations where (in case of really long delays in slotReadyRead and a lot of data coming) you can experience an overrun within OS FIFO buffers (for example for serial ports) but that has more to do with a bad software design rather then QT or OS problems.
You should look on slots like readyRead like on a interrupt handlers and keep their logic only within fetch functionality which fills your internals buffers while processing should be done in separate threads or while application on idle etc.. Reason is that any such application in general is a mass service system and if it spends more time on serving one request then a time interval between two requests it's queue will overrun anyway.
Second scenario: multithreaded application
Actually this scenario is not that much differ from 1) expect that you should design right what happens in each of your threads. If you keep main loop with light wighted 'pseudo interrupt handlers' you will be absolutely fine and keep processing logic in other threads, but this logic should work with your own prefetch buffers rather then with QIODevice.
The problem is quite interesting.
In my program the usage of QTcpSocket is very intensive. So I've written the whole library, that breaks outgoing data into packages with a header, data identifier, package index number and maximum size, and when the next piece of data comes, I know exactly where it belongs to. Even if I miss something, when the next readyRead comes, the receiver reads all and compose received data correctly. If the communication between your programs is not so intense, you could do the same, but with timer (which is not very fast, but solves the problem.)
About your solution. I don't think it's better then this:
void readSocketData()
{
while(socket->bytesAvailable())
{
datacounter += socket->readAll().length();
qDebug() << datacounter;
QEventLoop loop;
QTimer::singleShot(1000, &loop, SLOT(quit()));
loop.exec();
}
}
The problem of both methods is the code right after leaving the slot, but before returning from emitting the signal.
Also you could connect with Qt::QueuedConnection.
Here are some examples of ways to get the whole file, but using some other parts of the QNetwork API:
http://qt-project.org/doc/qt-4.8/network-downloadmanager.html
http://qt-project.org/doc/qt-4.8/network-download.html
These examples show a stronger way to handle the TCP data, and when buffers are full, and better error handling with a higher level api.
If you still want to use the lower level api, here is a post with a great way to handle the buffers:
Inside your readSocketData() do something like this:
if (bytesAvailable() < 256)
return;
QByteArray data = read(256);
http://www.qtcentre.org/threads/11494-QTcpSocket-readyRead-and-buffer-size
EDIT: Additional examples of how to interact with QTCPSockets:
http://qt-project.org/doc/qt-4.8/network-fortuneserver.html
http://qt-project.org/doc/qt-4.8/network-fortuneclient.html
http://qt-project.org/doc/qt-4.8/network-blockingfortuneclient.html
Hope that helps.
If a QProgressDialog shall be shown while receiving data from a socket it only works if any QApplication::processEvents() are sent (e.g. by the QProgessDialog::setValue(int) methode). This of course leads to the loss of readyRead signals as mentioned above.
So my workaround was a while loop including the processEvents command such as:
void slot_readSocketData() {
while (m_pSocket->bytesAvailable()) {
m_sReceived.append(m_pSocket->readAll());
m_pProgessDialog->setValue(++m_iCnt);
}//while
}//slot_readSocketData
If the slot is called once any additional readyRead signals can be ignored because the bytesAvailable() always returns the actual number after the processEvents call. Only on pausing of the stream the while loop ends. But then the next readReady is not missed and starts it again.
I had the same problem right away with the readyRead slot. I disagree with the accepted answer; it doesn't solve the problem. Using bytesAvailable as Amartel described was the only reliable solution I found. Qt::QueuedConnection had no effect. In the following example, I'm deserializing a custom type, so it's easy to predict a minimum byte size. It never misses data.
void MyFunExample::readyRead()
{
bool done = false;
while (!done)
{
in_.startTransaction();
DataLinkListStruct st;
in_ >> st;
if (!in_.commitTransaction())
qDebug() << "Failed to commit transaction.";
switch (st.type)
{
case DataLinkXmitType::Matrix:
for ( int i=0;i<st.numLists;++i)
{
for ( auto it=st.data[i].begin();it!=st.data[i].end();++it )
{
qDebug() << (*it).toString();
}
}
break;
case DataLinkXmitType::SingleValue:
qDebug() << st.value.toString();
break;
case DataLinkXmitType::Map:
for (auto it=st.mapData.begin();it!=st.mapData.end();++it)
{
qDebug() << it.key() << " == " << it.value().toString();
}
break;
}
if ( client_->QIODevice::bytesAvailable() < sizeof(DataLinkListStruct) )
done = true;
}
}
i got the same problem, rather use signal readyRead() and socket.readall, i' m trying the following, just after connect without be sure :
QByteArray RBuff;
if(m_socket->waitForConnected(3000))
{
while (m_socket->ConnectedState == QAbstractSocket::ConnectedState) {
RBuff = m_socket->read(2048);
SocketRead.append(RBuff);
if (!SocketRead.isEmpty() && SocketRead.length() == 2048)
{
readData(SocketRead);
SocketRead.remove(0,2048);
}
QCoreApplication::processEvents(QEventLoop::AllEvents, 100);
}
//m_socket->close();*/
}
else
{

Problems with reading data from QTcpSocket

I've modified the threaded fortune-server from Qt examples.
The client connects to the server and then sends a header to authenticate.
tcpSocket = new QTcpSocket();
tcpSocket->connectToHost(addr, port);
QByteArray block = "someheader";
int x = tcpSocket->write(block);
qDebug() << x;
The client seems OK here and qDebug prints the actual size of block.
On the server side I've predefined incomingConnection and I start thread to each new connection.
void Server::incomingConnection(int socketDescriptor) {
const QString &str = vec[qrand() % vec.size()];
SpellThread *thread = new SpellThread(socketDescriptor, str);
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
qDebug() << " -- incoming connection";
thread->start();
}
I'm connecting sock to check is there something to read. (sock here is QTcpServer*)
void SpellThread::run() {
qDebug() << " -- in spellthread";
connect(sock, SIGNAL(readyRead()), this, SLOT(checkBytes()));
//....
qDebug() << " -- end spellthread";
}
The first problem is that when I'm sending data from the client, readyRead is not fired. (I've added debug message in checkBytes)
Messages are:
-- incoming connection
-- in spellthread
-- end spellthread
Although the client prints the actual size of header length.
The second problem is that checkBytes currently is very bad-designed. First it checks is header OK and sets a flag, then it gets the size of message and sets another flag and finally it gets the real message. This is very clumsy. I first tried to escape signals and instead use sock->waitForReadyRead(). However it always returns false. (From the docs: "Reimplement this function to provide a blocking API for a custom device. The default implementation does nothing, and returns false.").
So how to really make a client/server application in Qt with multiple clients and multiple reads/writes? I really want suggestions to improve design of my application and to solve my current two problems.
You can't use slots or socket signals with a thread without calling QThread::exec() to start an event loop within that thread/the run function.
Since your checkBytes slot belongs to QThread, it wouldn't be executed by the thread (there is a detailed article about QThreads here)
The closest example that seems to already do what you want is the Network Chat (particularly the two classes Server and Connection).
----------Edit
If you need to use threads (without any slot), the QTcpSocket object must belongs to the same thread as the one where you call waitForReadyRead. For example, with:
SpellThread::SpellThread(int socketDescriptor, const QString & str) {
tcpSocket = new QTcpSocket(); // There should be no parent to be able
// to move it to the thread
tcpSocket->moveToThread(this);
...
Or by creating the QTcpSocket object inside the run function so that it automatically belongs to that thread (it was briefly explained in the fortune example).
If you allocate the QTcpSocket dynamically, and because it won't have a parent, you should also delete it manually.