I have QTcpServer. I want to send large data from client side and how to catch signal, when all data is received on server?
"while (socket->bytesavailable)" doesn't work.
For example:
when qbytearray size is 9000, which is send from client, on the server it's 4000 or 5000...
Example Two:
In this Case readyRead() SIGNAL Is Emited 8 times.
void Client::SendMessage(std::vector<QString>)
{
MyClass _Send;
_Send.Age = 22;
_Send.School = 14;
_Send.Name = "Taz";
QVector<MyClass2> vv;
for (int i = 0; i < 15000; i++) {
vv.push_back(MyClass2(24, "leri"));
vv.push_back(MyClass2(22, "tazo"));
}
_Send.vctr = vv;
QByteArray bytes;
QDataStream stream(&bytes, QIODevice::WriteOnly);
int FunctionUID = 331;
int ij, ik = ij = 169;
MyClass2 faf(-31, "15");
stream << FunctionUID << _Send << faf << ij << ik;
socket->write(bytes);
}
void Server::ImReady()
{
QByteArray buf;
buf = socket->readAll();
QDataStream stream(&buf, QIODevice::ReadOnly);
int FunctionUID, ij, ik;
MyClass vv;
MyClass2 vv1;
stream >> FunctionUID >> vv >> vv1 >> ij >> ik;
qDebug() << vv.vctr.size() << "faf";
}
void Server::incomingConnection(qintptr val)
{
qDebug() << "Client Connected" << val;
socket = new QTcpSocket;
socket->setSocketDescriptor(val);
if (!socket) {
return;
}
connect(socket, SIGNAL(disconnected()), socket, SLOT(deleteLater()));
connect(socket, SIGNAL(readyRead()), this, SLOT(ImReady()));
}
TCP does not send messages, it is a stream of data. This means you can't just read all data that's there, and consider this one message. Instead one usually sends a header, containing the message size, and then the receiver knows how much to read to get the whole message (and just this one, not read into the next).
This means your slot would do something like this
void Server::ImReady()
{
uint32 size;
socket->read(&size, 4);
uint32 readTotal = 0;
do {
readTotal += socket->read(buffer, size-readTotal);
} while (readTotal < size);
}
You could put a line like
if (socket->bytesAvailable() == 0)
return;
at the beginning of the slot, and then you would not care at all if the signal is emitted more than once per message.
Note that the code above needs additional error handling, e.g. you must make sure the first read reads all 4 bytes, and always handle a return value of -1.
Related
My program is reading a configuration-file lines in a loop, and do a audio-recording for time = lines*100ms.
But for 5 same config-files I get 5 different length. (For 5sek recordings +-100ms)
I trying to change QThread::msleep(1500); or to declare QEventLoop and QTimer outside a loop, but there are no changes.
How can I get the recordings with right times?
Audio.cpp
// ************************************************************************************************
// Audio-Class
// ************************************************************************************************
#include "Audio.h"
#include "Measure.h"
#include <QAudioInput>
#include <QTimer>
// ************************************************************************************************
Audio::Audio()
{
QTimer *m_timer = new QTimer(this);
m_timer->setSingleShot(true);
AudioRecord();
}
// ************************************************************************************************
//Initialization and signal-slot connection
void Audio::AudioRecord()
{
//Set audio configuration
QAudioFormat format;
format.setSampleRate(44100);
format.setChannelCount(1);
format.setSampleSize(16);
format.setCodec("audio/PCM");
format.setByteOrder(QAudioFormat::LittleEndian);
format.setSampleType(QAudioFormat::SignedInt);
//Wrong configuration detection
QAudioDeviceInfo info = QAudioDeviceInfo::defaultInputDevice();
if (!info.isFormatSupported(format))
{
qWarning() << "Default format not supported";
format = info.nearestFormat(format);
}
//Signal-slot connection to show actual Audio state or errors output
m_audio = new QAudioInput(format, this);
connect(m_audio, SIGNAL(stateChanged(QAudio::State)), this, SLOT(handleStateChanged(QAudio::State)));
}
// ************************************************************************************************
//Start recording
//void Audio::StartRecording(QString rec_file_path)
void Audio::StartRecording(QString rec_file_path, quint32 record_time_msec)
{
m_file.setFileName(rec_file_path); //audio recording path format
m_file.open(QIODevice::WriteOnly); //audio access mode initialisation
writeHeader(); //writing header to convert PCM to *.wav (Step 1)
m_audio->start(&m_file); //start recording
//QTimer::singleShot((15000), this, SLOT(StopRecording()));
QTimer::singleShot((record_time_msec), this, SLOT(StopRecording()));
QCoreApplication::processEvents();
qDebug()<< m_audio->format();
//qDebug()<< m_file.open();
QAudioDeviceInfo::defaultInputDevice();
QAudioDeviceInfo::availableDevices(QAudio::AudioInput);
//qDebug()<< m_audio->error();
//qDebug()<< m_audio->notifyInterval();
}
// ************************************************************************************************
//Write Header
// ************************************************************************************************
void Audio::writeHeader(){
quint64 data64 = 0;
quint32 data_Filesize_fill = 0;
quint32 data_lenght = 16;
quint16 data_PCM = 1;
quint16 data_Chanel = 1;
quint32 data_SamplRate = 44100;
quint32 data_Value = (44100 * 16 * 1)/8;
quint16 data_mono = (16 * 1)/8;
quint16 data_BPS = 16;
quint32 data_FileSize = 44;
m_file.write("RIFF",4);
m_file.write((char*)&data_Filesize_fill, 4);
m_file.write("WAVE",4);
m_file.write("fmt ",4); // "fmt " chunk size (always 16 for PCM)
m_file.write((char*)&data_lenght, 4);
m_file.write((char*)&data_PCM, 2);
m_file.write((char*)&data_Chanel, 2);
m_file.write((char*)&data_SamplRate, 4);
m_file.write((char*)&data_Value, 4); // bytes per second
m_file.write((char*)&data_mono, 2); // Block align
m_file.write((char*)&data_BPS, 2); // Bits per sample
m_file.write("data",4);
m_file.write((char*)&data_FileSize, 4);
m_file.flush();
}
// ************************************************************************************************
//Stop recording
void Audio::StopRecording()
{
m_audio->stop();
qDebug() << "stop";
writeHeaderFinal();
m_file.close();
qDebug() << "close";
}
// ************************************************************************************************
//Write Header
void Audio::writeHeaderFinal(){
quint32 data_Filesize_fill_after = m_file.size() - 8;
quint32 data_FileSize_after = m_file.size() - 44;
m_file.seek(4);
m_file.write((char*)&data_Filesize_fill_after, 4);
m_file.seek(40);
m_file.write((char*)&data_FileSize_after, 4);
}
// ************************************************************************************************
//Recording DEBUG output
void Audio::handleStateChanged(QAudio::State newState)
{
switch (newState)
{
case QAudio::StoppedState:
if (m_audio->error() != QAudio::NoError)
{
qDebug() << "Error audio recording!!";
} else
{
qDebug() << "Finished audio recording";
}
break;
case QAudio::ActiveState:
qDebug() << "Started audio recording";
break;
default:
break;
}
}
// ************************************************************************************************
Measure.cpp
// ************************************************************************************************
// Measure-Class
// ************************************************************************************************
//class initialisation
#include "Measure.h"
#include "Conf.h"
#include "Audio.h"
// ************************************************************************************************
Measure::Measure(Audio *audio)
{
//member variables init
m_audio = audio;
//UART-status debug
if (0 == connectSerial())
{
qDebug() << "Serial connection OK!\n";
}
else
{
qDebug() << "Serial connection Error!\n";
return;
}
auto info = QAudioDeviceInfo::availableDevices(QAudio::AudioInput);
foreach (auto i, info) qDebug() << i.deviceName();
//m_timer = new QTimer(this); double
//set serial connection
//connect(m_timer, SIGNAL(timeout()), this, SLOT(processMeas()),Qt::QueuedConnection);
measure_cnt = 0;
qDebug()<<"Starting programm";
}
// ************************************************************************************************
// Start measure
void Measure::start()
{
//QTimer *m_timer = new QTimer(this);
//m_timer->setSingleShot(true);
//m_timer->start(1000); 555
processMeas();
}
// ************************************************************************************************
// Serial connection initialization and signal-slot connection
uint32_t Measure::connectSerial(void)
{
//serial connection configuration
m_serial.setPortName("/dev/ttyACM0");
m_serial.setBaudRate(QSerialPort::Baud115200);
m_serial.setDataBits(QSerialPort::Data8);
m_serial.setParity(QSerialPort::NoParity);
m_serial.setStopBits(QSerialPort::OneStop);
m_serial.setFlowControl(QSerialPort::NoFlowControl);
if (!m_serial.open(QIODevice::ReadWrite))
return 1;
//einable serial connection
connect(&m_serial, SIGNAL(readyRead()), this, SLOT(readRequest()));
return 0;
}
// ************************************************************************************************
// State maschine
// ************************************************************************************************
void Measure::processMeas()
{
// Declaration ************************************************************
static uint32_t i = 0;
static uint32_t j = 0;
static uint8_t stm = 0;
static uint16_t m1 = 0;
static uint16_t m2 = 0;
static uint16_t m3 = 0;
static uint16_t m4 = 0;
static uint16_t var;
static QByteArray hextest;
// Read config files ***********************************************************************************
QDir directory("/home/nikitajarocky/workspace/QT/Software_2.0_QT/Config_files/");
QStringList config_files = directory.entryList(QStringList() << "*.config", QDir::Files);
config_files_cnt = config_files.count();
foreach(QString filename, config_files)
{
Conf *conf = new Conf(directory.absoluteFilePath(filename));
qDebug() << "Config file: " << filename << " is processed";
// Error message *************************
if(conf->getConf_lines().size() == 0)
{
qDebug()<<"Error conf file!!";
return;
}
// Prepare measure ****************************************************************
qDebug()<<"Debug: Prepare measure";
QStringList lines = conf->getConf_lines(); //read all rows of config files
record_time_100ms = lines.count()-9; // lines Audio config data + end lines
record_time_msec = record_time_100ms * 100; //msec conversion
for(i=0; i < (uint32_t)lines.length(); i++) //prepare single rows of config files
{
//uint32_t j = 0;
QString uart;
QString uart_hex;
if(i > 5 && i < lines.length())
{
QStringList speed_chunks = lines.at(i).split(","); //split rows by decimal point
m1 = speed_chunks.at(2).toInt();
m2 = speed_chunks.at(3).toInt();
m3 = speed_chunks.at(4).toInt();
m4 = speed_chunks.at(5).toInt();
hextest.resize(10);
hextest[0]=255;
hextest[1]=m1>>8;
hextest[2]=m1;
hextest[3]=m2>>8;
hextest[4]=m2;
hextest[5]=m3>>8;
hextest[6]=m3;
hextest[7]=m4>>8;
hextest[8]=m4;
hextest[9]=238;
qDebug()<< "Transfer data: " << i-8 << " from " << lines.count()-9 << " rows transmitted";
qDebug() << "Config file: " << filename << " is processed";
m_serial.write(hextest);
m_serial.waitForBytesWritten(1000);
QThread::usleep(50000);
}//if(lines.at(i).contains(",")) end }//for end
}//for end
//Beep
// Measurement ******************************************************************
qDebug()<<"Debug: Measurement in progress";
QEventLoop event_loop(this); //create method class QEventLoop
QTimer exit_timer(this); //create method class QTimer
exit_timer.setSingleShot(true); //set timer in mode singleShot
connect(&exit_timer, SIGNAL(timeout()), &event_loop, SLOT(quit())); //connect exit timer to event loop slot
QThread::msleep(1500);
QString path = SAVE_AUDIO_PATH+filename.left( filename.lastIndexOf( '.' ) )+"_"+QDateTime::currentDateTime().toString("yyyyMMdd_hhmmss");
//QThread::msleep(1500);
m_file.setFileName(path+".log");
//m_audio->StartRecording(path+".wav");
m_audio->StartRecording(path+".wav", record_time_msec);//+0.6
//exit_timer.start(15000);
exit_timer.start(record_time_msec);//event loop timer durring measure time
event_loop.exec();
qDebug()<<"Measurement takes " << record_time_msec << " seconds";
// Stop measure ************************************
QThread::msleep(2000);
stm=0;
record_time_msec = 0;
measure_cnt++;
// All configs files done *********************************
if(measure_cnt>=config_files_cnt)
{
qDebug()<<"All measure done";
qApp->quit();
}
}//foreach
}//processMeas()
// ************************************************************************************************
// Data from STM32 receive
void Measure::readRequest()
{
m_file.open(QIODevice::WriteOnly | QIODevice::Append);
m_file.write(m_serial.readAll());
m_file.close();
}
// ************************************************************************************************
// save received data to log File
void Measure::saveFile(QByteArray buffer)
{
m_file.write(buffer);
}
Recordings are always little bit longer, so its a not stochastic error :
On the picture are 4 same config-files, two time
EDIT:
I change a code to:
m_audio->StartRecording(path+".wav", record_time_msec+5000);
exit_timer.start(record_time_msec+5000);//event loop timer
event_loop.exec();
an get:
But how can I start my measure delayed? (I want to skip beginning Sound (Buzzer))?
all
I want to use QUdpSocket to send udp packet to get config parameter from specific server,but It failed and I can not capture the sending packet using wireshark.here is my code:
CGetConfig.cpp:
CGetConfig::CGetConfig(const QString &conf_server,const uint16_t port)
:m_conf_server(conf_server)
,m_port(port)
{
m_socket = NULL;
}
CGetConfig::~CGetConfig()
{}
void CGetConfig::init()
{
// create a QUDP socket
m_socket = new QUdpSocket(this);
m_socket->bind(QHostAddress::LocalHost, 12345);
connect(m_socket, SIGNAL(readyRead()), this, SLOT(readyRead()));
m_ip_addr = get_ip_address(m_conf_server);
}
bool CGetConfig::get_reflector(const QString &mac)
{
qDebug() << "CGetConfig::get_reflector():Entry\n";
if(m_ip_addr.isEmpty())
{
qDebug() << "CGetConfig::get_reflector():ip address of cofnig server could not be resolved\n";
return 0;
}
QString msg("id=1&mac=");
msg+= mac;
msg+= "&get_config=fw_type=v.1,cfg_ver=4,set_ver=0,ip=192.168.1.101";
qDebug() << m_ip_addr;
qDebug() << m_port;
qDebug() << msg.toLatin1();
int count = 0;
while(count < 3)
{
int t = m_socket->writeDatagram(msg.toLatin1(), QHostAddress(m_ip_addr), m_port);
count++;
}
}
Main.cpp
CGetConfig cfg(cfg_server,cfg_port);
cfg.init();
local_mac = "00d033120001";
cfg.get_reflector(local_mac);
Can anyone help me figure out the problem?
I have a Client/Server based Qt application, using QTcpServer and QTcpSocket, I managed to do the connection and send some data back and forth between the client and the server.
The client sends many types of data to the server (string, int, files and a real time audio stream) and since my server impliment a single data input SLOT (readyRead()):
connect(socket, SIGNAL(readyRead()),this, SLOT(readyRead()));
I don't know how could I distinguish between all this received data and call respectively the right function in the server.
Example (in the server):
- if I receive string => call function showData(QString data);
- if I receive file => call function saveFile(QFile file);
- if I receive audio stream => play audio stream
- ...
SERVER:
void Server::newClientConnection()
{
QTcpSocket *socket = server->nextPendingConnection();
connect(socket, SIGNAL(readyRead()), this, SLOT(readyRead()));
//...
}
void Server::readyRead()
{
QTcpSocket *clientSocket = qobject_cast<QTcpSocket *>(sender());
if (clientSocket == 0) {
return;
}
QDataStream in(clientSocket);
if (sizeMessageClient == 0)
{
if (clientSocket->bytesAvailable() < (int)sizeof(quint16)){
return;
}
in >> sizeMessageClient;
}
if (clientSocket->bytesAvailable() < sizeMessageClient) {
return;
}
sizeMessageClient = 0;
in >> data;
/*
I don't know the type of the received data !!
- if I receive string => call function showData(QString data);
- if I receive file => call function saveFile(QFile file);
- if I receive audio stream => play audio stream
- ...
*/
}
CLIENT:
Client::Client()
{
socket = new QTcpSocket(this);
connect(socket, SIGNAL(readyRead()), this, SLOT(readyRead()));
sizeMessageServer = 0;
}
void Client::readyRead()
{
QDataStream in(socket);
if (sizeMessageServer == 0)
{
if (socket->bytesAvailable() < (int)sizeof(quint16)) {
return;
}
in >> sizeMessageServer;
}
if (socket->bytesAvailable() < sizeMessageServer) {
return;
}
int messageReceived;
in >> messageReceived;
messageReceived = static_cast<int>(messageReceived);
sizeMessageServer = 0;
switch(messageReceived)
{
case 1:
qDebug() << "send a File";
sendFile();
break;
case 2:
qDebug() << "send a string data";
sendStringData();
break;
case 3:
qDebug() << "stream audio to the server";
streamAudioToServer();
break;
case n:
// ...
}
}
I am not looking for a complete solution, all I am looking for is some guidance in the right direction.
The implementation of your protocol doesn't fully leverage QDataStream in Qt 5.7. Here's how it might look now - it can be quite simple.
First, let's define the requests we know of:
enum class Req : quint32 {
Unknown, String, File
};
Q_DECLARE_METATYPE(Req)
QDataStream & operator<<(QDataStream & ds, Req req) {
return ds << (quint32)req;
}
QDataStream & operator>>(QDataStream & ds, Req & req) {
quint32 val;
ds >> val;
if (ds.status() == QDataStream::Ok)
req = Req(val);
return ds;
}
It'd also be handy to have a transaction RAII helper.
struct Transaction {
QDataStream & stream;
Transaction(QDataStream & stream) : stream{stream} {
stream.startTransaction();
}
~Transaction() {
stream.commitTransaction();
}
bool ok() {
return stream.status() == QDataStream::Ok;
}
};
The client receives requests from the server and signals the need to reply with data. The code that uses the client would react to these signals and reply back by invoking a matching slot. E.g.
void clientUser(Client & client) {
QObject::connect(&client, &Client::needString, &client, [&]{
client.sendString(QStringLiteral{"You got string!"});
});
And:
class Client : public QObject {
Q_OBJECT
QIODevice & m_dev;
QDataStream m_str{&m_dev};
void onReadyRead() {
Transaction tr{m_str};
Req req;
m_str >> req;
if (!tr.ok()) return;
if (req == Req::String)
emit needString();
else if (req == Req::File) {
QString fileName;
m_str >> fileName;
if (!tr.ok()) return;
emit needFile(fileName);
}
else emit unknownRequest(req);
}
public:
Client(QIODevice & dev) : m_dev{dev} {
connect(&m_dev, &QIODevice::readyRead, this, &Client::onReadyRead);
}
Q_SIGNAL void unknownRequest(Req);
Q_SIGNAL void needString();
Q_SIGNAL void needFile(const QString & fileName);
Q_SLOT void sendString(const QString & str) {
m_str << Req::String << str;
}
Q_SLOT void sendFile(const QString & fileName, const QByteArray & data) {
m_str << Req::File << fileName << data;
}
};
The server is very similar. Its user sends the request to a client via request slots. Once the server hears back from the client, it indicates it through the has signals:
class Server : public QObject {
Q_OBJECT
QIODevice & m_dev;
QDataStream m_str{&m_dev};
void onReadyRead() {
Transaction tr{m_str};
Req req;
m_str >> req;
if (!tr.ok()) return;
if (req == Req::String) {
QString str;
m_str >> str;
if (!tr.ok()) return;
emit hasString(str);
}
else if (req == Req::File) {
QString fileName;
QByteArray data;
m_str >> fileName >> data;
if (!tr.ok()) return;
emit hasFile(fileName, data);
}
else emit hasUnknownRequest(req);
}
public:
Server(QIODevice & dev) : m_dev{dev} {
connect(&m_dev, &QIODevice::readyRead, this, &Server::onReadyRead);
}
Q_SIGNAL void hasUnknownRequest(Req);
Q_SIGNAL void hasString(const QString &);
Q_SIGNAL void hasFile(const QString & name, const QByteArray &);
Q_SLOT void requestString() {
m_str << Req::String;
}
Q_SLOT void requestFile(const QString & name) {
m_str << Req::File << name;
}
};
The program is able to send .txt files. But any other filetype gets corrupted. I think it has something to do with the datatypes I store my frames in. Sorry for the long post i just have no idea where my problem might be.
I'm new to QT as well as C++. I HAVE TO use QUdpSocket to send any file over a network to another computer. This computer should then reassemble the datagrams in the correct order and save it as a file. (QFiles have to be broken up in segments with sequence number headers and reassembled according to these numbers). Segments are stored with their sequence number in a QByteArray array.
//Setup File
filelocation= opendialog->getOpenFileName(this, "Select File to be sent", "C:/Users/<USER>/Desktop");
SentFile.setFileName(filelocation);
if (!(SentFile.open(QIODevice::ReadOnly))){
return;
}
//Setup Datastream
SentData.setDevice(&SentFile);
SentData.setByteOrder(QDataStream::BigEndian);
SentData.setFloatingPointPrecision(QDataStream::SinglePrecision);
SentData.setVersion(QDataStream::Qt_5_5);
//Calculate number of frames to be sent
max_framesize=200;
int length=SentFile.size();
dsize=length/max_framesize+1;
if((length%max_framesize)!=0)
dsize++;
//Write initial message with dsize and file name
char BeginMessage[max_framesize+16];
char *cfile= new char[filelocation.length()+1];
strcpy(cfile, filelocation.toStdString().c_str());
sprintf(BeginMessage,"%016d%010d%s",0, dsize-1, cfile);
SendArray[0]= BeginMessage;
int i=1;
while(SentData.atEnd()!=true)
{
char s[max_framesize+1];
int len = SentData.readRawData(s, max_framesize);
for(int n=len; n<=max_framesize;n++)
{
s[n]='\0';
}
char tempframe[17];
sprintf(tempframe,"%016d",i);
tempframe[16]='\0';
SendArray[i]=s;
SendArray[i].prepend(tempframe);
i++;
}
The QByteArray Array is then sent over the qudpsocket
void MainWindow::on_pushButton_clicked()
{
for(int l=0; l<dsize; l++)
{
QByteArray datagram = SendArray[l];
socket->writeDatagram(datagram.data(), QHostAddress::Broadcast, 5743);
}
ui->lineEdit->clear();
ui->lineEdit->setFocus();
}
The Reassembly code works as follows
void MainWindow::receiveData()
{
while (socket->hasPendingDatagrams())
{
FramesReceived++;
QByteArray datagram;
datagram.resize(socket->pendingDatagramSize());
QHostAddress sender;
quint16 senderPort;
socket->readDatagram(datagram.data(), datagram.size(),
&sender, &senderPort);
char temp[datagram.size()];
strcpy(temp, datagram);
char cseq_num[17];
for(int n=0; n<16;n++)
{
cseq_num[n]=temp[n];
}
cseq_num[16]='\0';
datagram.remove(0,16);
int seq_num = atoi(cseq_num);
if(seq_num==0)
{
char size[11];
for(int n=0; n<10;n++)
{
size[n]=temp[n+16];
}
size[11]='\0';
rsize = atoi(size);
QByteArray Name=datagram;
Name.remove(0, 10);
strcpy(OriginalName,Name.data());
}
ReceivedArray[seq_num]= datagram;
char message[600];
sprintf(message,"%d of %d Frames Received\nFile name: %s",FramesReceived,rsize, OriginalName);
ui->label->setText(message);
}
}
After all frames have been received
void MainWindow::on_pushButton_3_clicked()
{
filelocation= opendialog->getSaveFileName(this, "Save File");
ReceivedFile.setFileName(filelocation);
if (!(ReceivedFile.open(QIODevice::WriteOnly))){
return;
}
char snum[27];
for(int n=0; n<27;n++)
{
snum[n]=ReceivedArray[0][n];
}
snum[27]='\0';
int len_num = atoi(snum);
ReceivedData.setDevice(&ReceivedFile);
ReceivedData.setByteOrder(QDataStream::BigEndian);
ReceivedData.setFloatingPointPrecision(QDataStream::SinglePrecision);
ReceivedData.setVersion(QDataStream::Qt_5_5);
for(int i=1; i<len_num; i++)
{
ReceivedData.writeRawData(ReceivedArray[i],ReceivedArray[i].length());
}
ReceivedData.writeRawData(ReceivedArray[len_num],ReceivedArray[len_num].length());
ReceivedFile.close();
}
I am attempting to build my own custom QAbstractNetworkCache implementation for use with QNetworkAccessManager.
I am having trouble with QAbstractNetworkCache::insert(QIODevice *device); inside this method, the device always arrives with 0 bytes to read from.
As I understand, the QIODevice* that is returned from QAbstractNetworkCache::prepare(const QNetworkCacheMetaData &metaData) is going to be filled with data and used as a parameter to QAbstractNetworkCache::insert(QIODevice *device) method once QNetworkAccessManager finishes downloading.
So I have prepared a QBuffer to be this container, but whenever QAbstractNetworkCache::insert(QIODevice *device) is getting called, it always arrives with nothing in it (device->bytesAvailable() == 0)
QIODevice* NetworkCachePrivate::prepare(const QNetworkCacheMetaData &metaData) {
if (!metaData.isValid() || !metaData.url().isValid() || cacheDir.isEmpty()) return 0;
QIODevice* device = 0;
QString hash = hexMD5(metaData.url().toString());
QScopedPointer<QBuffer> buffer(new QBuffer);
if (buffer->open(QIODevice::ReadWrite))
{
qDebug() << "BUFFER READY";
device = buffer.take();
deviceMapping[device] = qMakePair(hash, metaData);
}
return device;
}
void NetworkCachePrivate::insert(QIODevice *device) {
if (deviceMapping.contains(device))
{
QPair<QString, QNetworkCacheMetaData> pair = deviceMapping[device];
QString fileName;
fileName += cacheDir;
fileName += QLatin1String("/");
fileName += pair.first;
qDebug() << "DEVICE BYTES" << device->bytesAvailable(); //ALWAYS 0!!!! :(
QFile file(fileName);
if (file.open(QIODevice::WriteOnly))
{
qint64 size = file.write(device->readAll());
if (size <= 0)
{
file.remove();
}
else
{
qDebug() << "FILE WROTE " << size;
cacheSize += size;
}
}
deviceMapping.remove(device);
delete device;
}
}
QNetworkCacheMetaData NetworkCachePrivate::metaData (const QUrl &url ) {
QString fileName;
fileName += cacheDir;
fileName += QLatin1String("/");
fileName += hexMD5(url.toString());
QNetworkCacheMetaData data;
if (!QFile::exists(fileName))
return data;
data.setUrl(url);
data.setExpirationDate(QDateTime::currentDateTime().addYears(1));
return data;
}
As peppe also pointed out in the comment, you need to seek the QBuffer to the beginning after the write and before the read as per the documentation:
QBuffer allows you to access a QByteArray using the QIODevice interface. The QByteArray is treated just as a standard random-accessed file. Example:
QBuffer buffer;
char ch;
buffer.open(QBuffer::ReadWrite);
buffer.write("Qt rocks!");
*** buffer.seek(0); ***
buffer.getChar(&ch); // ch == 'Q'
buffer.getChar(&ch); // ch == 't'
buffer.getChar(&ch); // ch == ' '
buffer.getChar(&ch); // ch == 'r'
To be more concrete for your code, you would need to insert the statement like this:
...
device.seek(0);
qDebug() << "DEVICE BYTES" << device->bytesAvailable(); //NOT 0 ANYMORE!!!! :)
...