I'm using QT. I need to broadcast data, so I try to use QUdpSocket. But data can be too big(after writeDatagram QUdpSocket::error returns DatagramTooLargeError). So I split data and call writeDatagram several times to the parts. But Received socket receive data only once, only first packet. Receive code is
connect(&m_socketReceiver, &QUdpSocket::readyRead, this, &LocalNetSharing::onDataRead);
void LocalNetSharing::onDataRead()
{
while (m_socketReceiver.hasPendingDatagrams())
{
QByteArray datagram;
datagram.resize(m_socketReceiver.pendingDatagramSize());
m_socketReceiver.readDatagram(datagram.data(), datagram.size());
//process data
}
}
From the Qt documentation about QUdpSocket Class :
Note: An incoming datagram should be read when you receive the
readyRead() signal, otherwise this signal will not be emitted for the
next datagram.
So it seems that you are not reading the entire datagram in each call of onDataRead.
You don't specify host and port in readDatagram. I am not sure if it is the reason but the correct form is :
while (m_socketReceiver.hasPendingDatagrams())
{
QByteArray datagram;
datagram.resize(m_socketReceiver.pendingDatagramSize());
m_socketReceiver.readDatagram(datagram.data(), datagram.size(), host, &port);
//process data
}
Related
I am working on a Qt program that communicate with specific digital board with LAN and Serial Port, These packets should be read from LAN and send to other device connected to pc immediately. we have a problem with those packets come from serial port. we get these packets with emit on readyRead Signal and using readAll function for reading QByteArray inside the connected Slot. the problem is: delay on reading packets. I want to change the signal/slot mechanism to producer/costumer queue mechanism (using mutex for prevent critical section). Is queue mechanism faster than signal/slot or not?
Some code like below: this is not an executable function just present in pseudocode
func1Thread() //customer thread
{
while(!stopThread)
{
if(queueSize>0)
{
//parse packet
}
else
msleep(100);
}
}
func2Thread() //producer thread
{
while(!stopThread)
{
if(!socket.waitForReadyRead())
{
qByteArray ba= socket.readAll();
//enqueue here
}
}
}
thanks
I know that TCP guarantees that all packets will arrive. But can a packet be separated into 2 or more? I am using Qt with class QTcpSocket, and I want to know is ReadyRead() signal is emitted only when full packet arrives. Or in other words, is there any sense to send packet size in first bytes and then wait in loop until all bytes had arrived? Or I can just call socket->readAll() and I must get one full packet?
If a large amount of data is sent, the packet can arrive in separate parts. Alternatively, multiple messages can be received in one readyRead slot.
It's good practice to control this by setting the first byte(s) to the number of bytes that will be sent. Then, in readyRead, you read the first bytes and append the data to a buffer until the expected amount of data has been received.
In receiving data, this also means that if multiple messages are received in one call to readyRead(), you can know where the first message ends and the next one begins.
Here's an example of a client that receives data in a readyRead function()
void MyClass::readyRead()
{
// m_pConnection is a QTcpSocket
while(m_pConnection->bytesAvailable())
{
QByteArray buffer;
int dataSize;
m_pConnection->read((char*)&dataSize, sizeof(int));
buffer = m_pConnection->read(dataSize);
while(buffer.size() < dataSize) // only part of the message has been received
{
m_pConnection->waitForReadyRead(); // alternatively, store the buffer and wait for the next readyRead()
buffer.append(m_pConnection->read(dataSize - buffer.size())); // append the remaining bytes of the message
}
QString msg(buffer); // data in this case is JSON, so we can use a QString
emit Log(QString("\tMessage Received: %1").arg(msg));
// Do something with the message
ProcessMessage(msg);
}
}
I know that TCP guarantees that all packets will arrive. But can a packet be separated into 2 or more? I am using Qt with class QTcpSocket, and I want to know is ReadyRead() signal is emitted only when full packet arrives. Or in other words, is there any sense to send packet size in first bytes and then wait in loop until all bytes had arrived? Or I can just call socket->readAll() and I must get one full packet?
If a large amount of data is sent, the packet can arrive in separate parts. Alternatively, multiple messages can be received in one readyRead slot.
It's good practice to control this by setting the first byte(s) to the number of bytes that will be sent. Then, in readyRead, you read the first bytes and append the data to a buffer until the expected amount of data has been received.
In receiving data, this also means that if multiple messages are received in one call to readyRead(), you can know where the first message ends and the next one begins.
Here's an example of a client that receives data in a readyRead function()
void MyClass::readyRead()
{
// m_pConnection is a QTcpSocket
while(m_pConnection->bytesAvailable())
{
QByteArray buffer;
int dataSize;
m_pConnection->read((char*)&dataSize, sizeof(int));
buffer = m_pConnection->read(dataSize);
while(buffer.size() < dataSize) // only part of the message has been received
{
m_pConnection->waitForReadyRead(); // alternatively, store the buffer and wait for the next readyRead()
buffer.append(m_pConnection->read(dataSize - buffer.size())); // append the remaining bytes of the message
}
QString msg(buffer); // data in this case is JSON, so we can use a QString
emit Log(QString("\tMessage Received: %1").arg(msg));
// Do something with the message
ProcessMessage(msg);
}
}
I use this code to transfer a large file through a socket without spikes in memory usage:
connect(socket, SIGNAL(bytesWritten(qint64)), this, SLOT(refillSocketBuffer(qint64)));
refillSocketBuffer(128*1024);
}
void FtpRetrCommand::refillSocketBuffer(qint64 bytes)
{
if (!file->atEnd()) {
socket->write(file->read(bytes));
} else {
socket->disconnectFromHost();
}
}
This works fine with QTcpSocket, but with an encrypted QSslSocket, the bytesWritten() signal is emitted constantly, which causes my function to write to the socket all the time, way quicker than it can send the data though the socket, so eventually its memory usage goes to 400 MB and the OS kills it.
I just found the answer after some more digging, it was in the documentation actually. It seems that I should use encryptedBytesWritten() for SSL sockets instead:
Note: Be aware of the difference between the bytesWritten() signal and the encryptedBytesWritten() signal. For a QTcpSocket, bytesWritten() will get emitted as soon as data has been written to the TCP socket. For a QSslSocket, bytesWritten() will get emitted when the data is being encrypted and encryptedBytesWritten() will get emitted as soon as data has been written to the TCP socket.
So I needed to change this code:
connect(socket, SIGNAL(bytesWritten(qint64)), this, SLOT(refillSocketBuffer(qint64)));
to this:
if (socket->isEncrypted()) {
connect(socket, SIGNAL(encryptedBytesWritten(qint64)), this, SLOT(refillSocketBuffer(qint64)));
} else {
connect(socket, SIGNAL(bytesWritten(qint64)), this, SLOT(refillSocketBuffer(qint64)));
}
I am trying to send 2 request one by one at same time. My code is following (this is example code):
QTcpSocket client;
...
client->write(block);
client->write(block);
Problem is following. Server receives only first request. There is no second request. I sniffed using wireshark and see that there is no second request in tcp packets.
What must i do to send many requests via QTcpSocket one by one?
UPD: I inserted qDebug() << this->bytesAvailable() << "bytes"; to server in readyRead() and qDebug() << this->bytesToWrite(); after each client->write(block); in client. Also, I added this to client:
connect(this, SIGNAL(bytesWritten(qint64)), this, SLOT(bytesWritten(qint64)));
void Connection::bytesWritten(qint64 count)
{
qDebug() << count << "bytes written";
}
I send ORDER_STATUS_GET_LIST constant in first request and ORDER_GET_LIST in second. I added data output in server. I received first command.
There is output listing:
Client:
Sending ORDER_STATUS_GET_LIST
11 bytes to write
Sending ORDER_GET_LIST
68 bytes to write
68 bytes written
Server:
68 bytes
ORDER_STATUS_GET_LIST received
According to the documentation, you need to flush() the socket IF you don't return to the event loop between multiple writes.
The proper solution would be to buffer your blocks into, e.g., a QByteArray and send the buffer at once.
QTcpSocket client;
QByteArray buffer;
...
buffer << block;
buffer << block;
client->write(buffer);
I found solution myself. I think that somebody needs this too.
Solution is simple:
QTcpSocket client;
...
client->write(block);
client->flush();
client->write(block);
client->flush();
We need to flush qt socket buffer to net before fill it with another data.