Я испытываю некоторые затруднения из-за спокойного приложения; конкретно с классом QNetworkAccessManager. Я пытаюсь выполнить простую загрузку HTTP двоичного файла с помощью сообщения () метод QNetworkAccessManager. Документация указывает, что я могу дать подсказку к QIODevice для регистрации (), и что класс передаст данные, найденные в QIODevice. Это предлагает мне, чтобы я должен был смочь дать сообщение () указатель на QFile. Например:
QFile compressedFile("temp");
compressedFile.open(QIODevice::ReadOnly);
netManager.post(QNetworkRequest(QUrl("http://mywebsite.com/upload") ), &compressedFile);
Что, кажется, происходит в системе Windows, где я разрабатываю, это - то, что мое спокойное приложение продвигает данные из QFile, но затем не завершает запрос; это, кажется, находится, там ожидая большего количества данных для разоблачения из файла. Запрос сообщения не "закрывается", пока я вручную не уничтожаю приложение, в которой точке целый файл обнаруживается в моем конце сервера.
От некоторой отладки и исследования, я думаю, что это происходит, потому что чтение () операция QFile не возвращается-1 при достижении конца файла. Я думаю, что QNetworkAccessManager пытается читать из QIODevice, пока это не получает-1 от чтения (), в которой точке он предполагает, что больше нет данных и не закрывают запрос. Если это продолжает получать код возврата нуля от чтения (), QNetworkAccessManager предполагает, что могло бы быть больше прибытия данных, и таким образом, это заставляет ждать те гипотетические данные.
Я подтвердил с некоторым тестовым кодом, что чтение () операция QFile просто возвращает нуль после чтения в конец файла. Это, кажется, является несовместимым со способом, которым сообщением () метод QNetworkAccessManager ожидает, что QIODevice будет вести себя. Мои вопросы:
Любые предложения или подсказки ценились бы.
Обновление: оказывается, что у меня было две различных проблемы: один на стороне клиента и один на стороне сервера. На стороне клиента я должен был удостовериться, что мой объект QFile остался вокруг на время сетевой транзакции. Сообщение () метод QNetworkAccessManager сразу возвращается, но на самом деле сразу не закончен. Необходимо присоединить слот к законченному () сигнал QNetworkAccessManager определить, когда POST на самом деле закончен. В моем случае было достаточно легко иметь в наличии QFile более или менее постоянно, но я также присоединил слот к законченному () сигнал для проверки на ошибочные ответы с сервера.
Я присоединил сигнал к слоту как это:
connect(&netManager, SIGNAL(finished(QNetworkReply*) ), this, SLOT(postFinished(QNetworkReply*) ) );
Когда пришло время отправить мой файл, я записал, почтовый индекс как это (обратите внимание, что compressedFile является членом моего класса и так не выходит из объема после этого кода):
compressedFile.open(QIODevice::ReadOnly);
netManager.post(QNetworkRequest(QUrl(httpDestination.getCString() ) ), &compressedFile);
Законченный (QNetworkReply*) сигнал от QNetworkAccessManager инициировал мой постзаконченный (QNetworkReply*) метод. Когда это происходит, для меня безопасно закрыть compressedFile и удалить файл данных, представленный compressedFile. Для отладки целей я также добавил несколько printf () операторы, чтобы подтвердить, что транзакция является завершенной:
void CL_QtLogCompressor::postFinished(QNetworkReply* reply)
{
QByteArray response = reply->readAll();
printf("response: %s\n", response.data() );
printf("reply error %d\n", reply->error() );
reply->deleteLater();
compressedFile.close();
compressedFile.remove();
}
Так как compressedFile сразу не закрывается и не выходит из объема, QNetworkAccessManager может занять столько времени, сколько ему нравится передавать мой файл. В конечном счете транзакция является завершенной и мой постзаконченный (), метод называют.
Моя другая проблема (который также способствовал поведению, которое я видел, где транзакция, никогда не завершаемая), состояла в том, что код Python для моего веб-сервера не выставлял POST правильно, но это выходит за рамки моего исходного спокойного вопроса.
Вы создаете compressedFile
в стеке и передаете указатель на него вашему QNetworkRequest (и, в конечном итоге, вашему QNetworkAccessManager). Как только вы покидаете метод, в котором находитесь, compressedFile
выходит за пределы области видимости. Я удивлен, что он не падает на вас, хотя поведение не определено.
Вам необходимо создать QFile
в куче:
QFile *compressedFile = new QFile("temp");
Вам, конечно, нужно будет отслеживать его, а затем удалить
после завершения публикации или установить это как дочерний элемент 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());
ИМХО, это гораздо более локализовано и инкапсулировано, чем необходимость держать вокруг себя файл во внешнем классе.
Обратите внимание, что вы должны удалить первый connect()
, если у вас есть ваш postFinished(QNetworkReply*)
слот, в котором вы должны затем не забыть вызвать reply->deleteLater()
внутри него, чтобы вышеописанное работало.