In the example below sometimes the file is downloaded correctly, and sometimes, I'm getting these values in the qDebug() added into the downloadProgress lambda:
Percent complete: -1.08905e+09
Downloaded 11623330 of -1
And then the download fails, I mean it saves a zip file with 0 bytes.
QNetworkAccessManager *manager = new QNetworkAccessManager(this);
QNetworkRequest request;
// Random link just to test:
request.setUrl(
QUrl("https://github.com/FFmpeg/FFmpeg/archive/refs/tags/n5.0.2.zip"));
QNetworkReply *reply = manager->get(request);
connect(reply, &QNetworkReply::downloadProgress,
[this, reply](qint64 bytesReceived, qint64 bytesTotal)
{
qDebug() << "Downloaded " << bytesReceived << " of " << bytesTotal;
double percentComplete = (bytesReceived * 100.0) / bytesTotal;
qDebug() << "Percent complete: " << percentComplete;
});
connect(reply, &QNetworkReply::finished, [this, reply]()
{
if (reply->error() != QNetworkReply::NoError)
{
qDebug() << "Error: " << reply->errorString();
} else
{
QString fileName = "C:/Users/Raja/Downloads/file.zip";
QFile file(fileName);
if (file.open(QIODevice::WriteOnly))
{
file.write(reply->readAll());
file.close();
qDebug() << "File downloaded successfully";
} else
qDebug() << "Error: Unable to open the file";
}
reply->deleteLater();
});
What i'm missing?
Did you read the documentation?
It says that bytesTotal is -1 if the total size is unknown and
The download is finished when bytesReceived is equal to bytesTotal. At that time, bytesTotal will not be -1.
In other words: That behavior is expected and just means the download is still in progress. This probably happens when the server doesn't send a content-length header. See What's the "Content-Length" field in HTTP header?
Related
When debug code, never enter into lambda function. Why do I have this problem?
QNetworkRequest req = QNetworkRequest(url);
QNetworkReply *reply = m_manager->get(req);
QObject::connect(reply, &QNetworkReply::finished,[reply](){
qDebug() << "start => ";
if(reply ->error() == QNetworkReply::NoError) {
QByteArray response = reply->readAll();
qDebug() << "response => ";
qDebug() << QString(response);
return response;
} else {
QByteArray error = reply ->readAll();
return error;
}
});
This is the solution to my problem, must create a signal for return data.
QObject::connect(reply,&QNetworkReply::finished,this, [this, reply]() {
qDebug() << "Got reply finished";
if(reply ->error() == QNetworkReply::NoError) {
m_json= reply->readAll();
reply->deleteLater();
emit workResponseChanged(m_workJson);
} else {
m_json= reply ->readAll();
reply->deleteLater();
emit workResponseChanged(m_workJson);
}
});
return QByteArray();
I would have to send Modbus request for specific data, my problem is that I have to use mobile communication, wifi, connect to a custom electronic card, which is right in Modbus RTU.
My working code connecting to the electronic board:
#include "connessione.h"
#include <QModbusTcpClient>
#include <QVariant>
#include <QModbusDataUnit>
#include <QDebug>
connessione::connessione(QObject *parent) : QObject(parent)
{
qDebug() << "here debug " << "ok";
clientX = new QModbusTcpClient();
clientX->setConnectionParameter(QModbusDevice::NetworkAddressParameter, "192.168.222.1");
clientX->setConnectionParameter(QModbusDevice::NetworkPortParameter, 5555);
if (clientX->connectDevice())
{
qDebug() << "connected: " << clientX->state();
}
else
{
qDebug() << "ERRORE" << clientX->errorString();
}
}
void connessione::clickButton(){
QModbusDataUnit readUnit(QModbusDataUnit::HoldingRegisters, 0, 1); // just read input register 40006
//qDebug() << "readUnit" << readUnit.RegisterType;
qDebug() << "readUnit" << clientX->state();
if (auto *reply = clientX->sendReadRequest(readUnit, 255)) // client id 255
{
if (!reply->isFinished())
{
// connect the finished signal of the request to your read slot
qDebug() << "connected" << reply->errorString();
connect(reply, &QModbusReply::finished, this, &connessione::readReady);
}
else
{
qDebug() << "Errore" << reply->errorString();
delete reply; // broadcast replies return immediately
}
}
else
{
qDebug() << "Errore" << reply->errorString();
// request error
}
}
void connessione::readReady()
{
QModbusReply *reply = qobject_cast<QModbusReply *>(sender());
if (!reply)
return;
if (reply->error() == QModbusDevice::NoError)
{
const QModbusDataUnit unit = reply->result();
int startAddress = unit.startAddress(); // the start address,
int value = unit.value(0); // value of the start address + 0
qDebug() << "NESSUN ERRORE" << reply->errorString();
}
else
{
qDebug() << "Errore readReady" << reply->errorString();
// reply error
}
reply->deleteLater(); // delete the reply
}
log string TCP sent:
D/libmodbusMobile.so( 8042): (null):0 ((null)): qt.modbus: (TCP
client) Sent TCP PDU: 0x0300000001 with tId: 2
this is right: 0x0300000001
But unfortunately, my electronic card, the integrated firmware I can not modify, is right with Modbus RTU, so I should change 0x0300000001 to 0x010300000001C1C2 where C1 and C2 are the checksums.
I believe that QModbusDataUnit generate buffer to send. So how to change it? Exist manual solution where I build the buffer?
how to change it and create custom send buffer like the example?
Thanks
I want to see the results of a GET request. By my understanding, this code should do it. What am I doing wrong?
void getDoc::on_pushButton_2_clicked()
{
manager = new QNetworkAccessManager(this);
connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(replyFinished(QNetworkReply*)));
manager->get(QNetworkRequest(QUrl("http://www.google.com")));
}
void getDoc::replyFinished(QNetworkReply *reply)
{
qDebug() << reply->error(); //prints 0. So it worked. Yay!
QByteArray data=reply->readAll();
qDebug() << data; // This is blank / empty
QString str(data);
qDebug() << "Contents of the reply: ";
qDebug() << str; //this is blank or does not print.
}
The code compiles and runs fine. It just doesn't work.
Try modifying your replyFinished slot to look like this:
QByteArray bytes = reply->readAll();
QString str = QString::fromUtf8(bytes.data(), bytes.size());
int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
You can then print the statusCode to see if you are getting a 200 response:
qDebug() << QVariant(statusCode).toString();
If you are getting a 302 response, you are getting a status redirect. You will need to handle it like this:
if(statusCode == 302)
{
QUrl newUrl = reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
qDebug() << "redirected from " + replyUrl + " to " + newUrl.toString();
QNetworkRequest newRequest(newUrl);
manager->get(newRequest);
return;
}
I'm returning when encountering a status code of 302 since I don't want the rest of the method to execute.
I hope this helps!
So I want to upload a file using this code in qt:
QFile *file = new QFile(this->itemsToUpload.at(index));
QUrl url("http://leonardogalli.ch/beta/upload_single.php");
QNetworkRequest request(url);
QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
QHttpPart loginPart;
/* password */
loginPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"password\""));
loginPart.setBody("pass");
multiPart->append(loginPart);
loginPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"path\""));
loginPart.setBody(this->paths.at(index).toLocal8Bit());
qDebug() << this->paths.at(index).toLocal8Bit();
multiPart->append(loginPart);
QHttpPart filePart;
/* important that the files[] variable have the brackets, for PHP to interpret correctly */
filePart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"uploaded\"; filename=\""+ file->fileName() + "\""));
qDebug() << "form-data; name=\"file1\"; filename=\""+ file->fileName() + "\"";
file->open(QIODevice::ReadOnly);
//qDebug() << file->readAll();
filePart.setBodyDevice(file);
file->setParent(multiPart); // we cannot delete the file now, so delete it with the multiPart
multiPart->append(filePart);
QNetworkReply* reply = networkManager->post(request, multiPart);
this->currentReply = reply;
multiPart->setParent(reply); // delete the multiPart with the reply
QObject::connect(reply,SIGNAL(uploadProgress(qint64,qint64)), this, SLOT(uploadProgress(qint64,qint64)));
QObject::connect(reply, SIGNAL(finished()), this, SLOT(finished()));
QObject::connect(reply, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(downloadProgress(qint64,qint64)));
}
void UploadManager::uploadProgress(qint64 bytesSent, qint64 bytesTotal)
{
if(bytesSent!=0 && bytesTotal != 0)
{
qDebug() << "Uploaded:" << bytesSent << " bytes of total: " << bytesTotal << "diff to total: " << bytesTotal-this->totalSize;
qint64 bytesDiff = bytesSent - this->lastUlSize;
this->UlSize += bytesDiff;
this->lastUlSize = bytesSent;
int timeDiff = QDateTime::currentMSecsSinceEpoch()/1000-this->time;
if(timeDiff!= 0 && bytesSent!=0 && bytesTotal != 0)
{
qDebug() << "Uploadspeed: " << ((this->UlSize/timeDiff));
qint64 remainingUl = this->totalSize - this->UlSize;
qint64 speed = ((this->UlSize/timeDiff)); //Download Speed in B/s
int remainingTimeSec = remainingUl/speed;
qDebug() << "Remaining time: " << this->readableTime(remainingTimeSec) << " percentage: " << (this->UlSize/this->totalSize)*100;
float percentage = ((float)this->UlSize/(float)this->totalSize)*100;
emit uploadProg(this->niceSpeed(speed), this->readableTime(remainingTimeSec), percentage);
}
}
}
The problem is there is a really long delay between the last uploadProgress signal and the finished signal. According to this question this is due to the uploadProgress not being the progress when a chunk of data has finished uploading. So how would I get the real uploadProgress, when a chunk is finished uploading?
Update 1:
On mac it seems to work perfectly, so why wont it work on windows?
I want to see the results of a GET request. By my understanding, this code should do it. What am I doing wrong?
void getDoc::on_pushButton_2_clicked()
{
manager = new QNetworkAccessManager(this);
connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(replyFinished(QNetworkReply*)));
manager->get(QNetworkRequest(QUrl("http://www.google.com")));
}
void getDoc::replyFinished(QNetworkReply *reply)
{
qDebug() << reply->error(); //prints 0. So it worked. Yay!
QByteArray data=reply->readAll();
qDebug() << data; // This is blank / empty
QString str(data);
qDebug() << "Contents of the reply: ";
qDebug() << str; //this is blank or does not print.
}
The code compiles and runs fine. It just doesn't work.
Try modifying your replyFinished slot to look like this:
QByteArray bytes = reply->readAll();
QString str = QString::fromUtf8(bytes.data(), bytes.size());
int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
You can then print the statusCode to see if you are getting a 200 response:
qDebug() << QVariant(statusCode).toString();
If you are getting a 302 response, you are getting a status redirect. You will need to handle it like this:
if(statusCode == 302)
{
QUrl newUrl = reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
qDebug() << "redirected from " + replyUrl + " to " + newUrl.toString();
QNetworkRequest newRequest(newUrl);
manager->get(newRequest);
return;
}
I'm returning when encountering a status code of 302 since I don't want the rest of the method to execute.
I hope this helps!