Загрузка файла с помощью метода post() QNetworkAccessManager

у меня возникли проблемы с приложением Qt; в частности, с классом QNetworkAccessManager. Я пытаюсь выполнить простую HTTP-загрузку двоичного файла с помощью метода post () QNetworkAccessManager. В документации говорится, что я могу дать указатель на QIODevice to post () и что класс передаст данные, найденные в QIODevice. Это говорит мне о том, что я должен иметь возможность дать post() указатель на QFile. Для пример:

QFile compressedFile("temp");  
compressedFile.open(QIODevice::ReadOnly);  
netManager.post(QNetworkRequest(QUrl("http://mywebsite.com/upload") ), &compressedFile);  

то, что, кажется, происходит в системе Windows, где я разрабатываю это, заключается в том, что мое приложение Qt выталкивает данные из QFile, но затем не завершает запрос; кажется, он сидит там, ожидая появления дополнительных данных из файла. Запрос post не "закрыт", пока я вручную не убью приложение, и в этот момент весь файл отображается на моем сервере.

из некоторых отладки и исследований я думаю, что это происходит потому, что операция read () QFile не возвращает -1, когда вы достигаете конца файла. Я думаю, что QNetworkAccessManager пытается читать из QIODevice, пока он не получит -1 от read (), в этот момент он предполагает, что больше нет данных и закрывает запрос. Если он продолжает получать нулевой код возврата из read (), QNetworkAccessManager предполагает, что может быть больше данных, и поэтому он продолжает ждать этих гипотетических данных.

Я подтвердил с некоторым тестовым кодом, что read () операция QFile просто возвращает ноль после того, как вы прочитали до конца файла. Это кажется несовместимым с тем, как метод post() QNetworkAccessManager ожидает, что QIODevice будет вести себя. Мои вопросы:

  1. это какое-то ограничение с тем, как QFile работает под Windows?
  2. есть ли другой способ использовать QFile или QNetworkAccessManager для перемещения файла через post()?
  3. это не собираюсь работайте вообще, и мне нужно будет найти другой способ загрузить мой файл?

любые предложения или советы будут оценены.

обновление: получается, что у меня две разные проблемы: одна на стороне клиента и на стороне сервера. На стороне клиента я должен был убедиться, что мой объект QFile оставался в течение всей сетевой транзакции. Метод post () QNetworkAccessManager возвращается немедленно, но на самом деле не завершен немедленно. Вам нужно прикрепить слот к сигналу finished () QNetworkAccessManager, чтобы определить, когда сообщение фактически завершено. В моем случае было достаточно легко сохранить QFile более или менее постоянно, но я также прикрепил слот к готовому сигналу (), чтобы проверить ответы на ошибки с сервера.

я прикрепил сигнал к слоту, как это:

connect(&netManager, SIGNAL(finished(QNetworkReply*) ), this, SLOT(postFinished(QNetworkReply*) ) );  

когда пришло время отправить мой файл, я написал пост такой код (обратите внимание, что сжатый файл является членом моего класса и так не выйдут из области видимости после этого код):

compressedFile.open(QIODevice::ReadOnly);  
netManager.post(QNetworkRequest(QUrl(httpDestination.getCString() ) ), &compressedFile);  

завершенный(QNetworkReply*) сигнал от QNetworkAccessManager запускает мой метод postFinished(QNetworkReply*). Когда это произойдет, это безопасно для меня, чтобы закрыть сжатый файл и удалить файл данных, представленных сжатый файл. Для целей отладки я также добавил несколько операторов printf (), чтобы подтвердить, что транзакция завершена:

void CL_QtLogCompressor::postFinished(QNetworkReply* reply)  
{  
    QByteArray response = reply->readAll();  
    printf("response: %sn", response.data() );  
    printf("reply error %dn", reply->error() );  
    reply->deleteLater();  
    compressedFile.close();  
    compressedFile.remove();  
}  

С compressedFile не закрывается сразу и не выходит за рамки, QNetworkAccessManager может занять столько времени, сколько ему нравится, чтобы передать мой файл. В конце концов транзакция завершена, и вызывается мой метод postFinished ().

моя другая проблема (которая также способствовала поведению, которое я видел, где транзакция никогда не завершалась) заключалась в том, что код Python для моего веб-сервера не заполнял сообщение правильно, но это выходит за рамки моего исходного Qt вопрос.

2 ответов


при создании compressedFile в стеке и передача указателя на него вашему QNetworkRequest (и, в конечном счете, вашему QNetworkAccessManager). Как только вы оставите метод, в котором вы находитесь,compressedFile выходит за рамки. Я удивлен, что это не рушится на вас, хотя поведение не определено.

вам нужно создать QFile в куче:

QFile *compressedFile = new QFile("temp"); 

вам, конечно, нужно будет отслеживать его, а затем delete это после того, как сообщение завершено, или установить его как дитя QNetworkReply так что он будет уничтожен, когда ответ будет уничтожен позже:

QFile *compressedFile = new QFile("temp"); 
compressedFile->open(QIODevice::ReadOnly);

QNetworkReply *reply = netManager.post(QNetworkRequest(QUrl("http://mywebsite.com/upload") ), compressedFile); 
compressedFile->setParent(reply);

вы также можете запланировать автоматическое удаление файла, выделенного кучей, с помощью сигналов / слотов

QFile* compressedFile = new QFile(...);
QNetworkReply* reply = Manager.post(...);
// This is where the tricks is
connect(reply, SIGNAL(finished()), reply, SLOT(deleteLater());
connect(reply, SIGNAL(destroyed()), compressedFile, SLOT(deleteLater());

IMHO, он гораздо более локализован и инкапсулирован, чем необходимость хранить файл во внешнем классе.

обратите внимание, что вы должны удалить первый элемент connect() если у вас есть свой postFinished(QNetworkReply*) слот, в который вы должны потом не забыть позвонить reply->deleteLater() внутри него для выше, чтобы работать.