Pergunta

Estou tendo alguns problemas com um aplicativo QT; Especificamente com a classe QNetworkAccessManager. Estou tentando executar um simples upload http de um arquivo binário usando o método post () do QNetworkAccessManager. A documentação afirma que posso dar um ponteiro a um qiodevice para postar () e que a classe transmitirá os dados encontrados no Qiodevice. Isso me sugere que eu deveria ser capaz de dar um ponteiro a um QFILE. Por exemplo:

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

O que parece acontecer no sistema Windows, onde estou desenvolvendo isso, é que meu aplicativo QT empurra os dados do QFile, mas não preenche a solicitação; Parece estar sentado esperando que mais dados apareçam no arquivo. A solicitação de postagem não está "fechada" até que eu mate manualmente o aplicativo, momento em que o arquivo inteiro aparece no final do meu servidor.

De alguma depuração e pesquisa, acho que isso está acontecendo porque a operação read () do QFILE não retorna -1 quando você chega ao final do arquivo. Eu acho que o QNetworkAccessManager está tentando ler do Qiodevice até obter um -1 de read (), quando assume que não há mais dados e fecha a solicitação. Se continuar obtendo um código de retorno de zero de read (), o QNetworkAccessManager pressupõe que possa haver mais dados chegando e, portanto, continua esperando por esses dados hipotéticos.

Confirmei com algum código de teste que a operação read () do QFILE apenas retorna zero depois de ler até o final do arquivo. Isso parece ser incompatível com a maneira como o método post () do QNetworkAccessManager espera que um Qiodevice se comporte. Minhas perguntas são:

  1. Isso é algum tipo de limitação com a maneira como o QFile funciona no Windows?
  2. Existe alguma outra maneira de usar o QFILE ou QNETWORKACESSMANAGER para pressionar um arquivo via post ()?
  3. Isso não vai funcionar e terei que encontrar outra maneira de fazer upload do meu arquivo?

Quaisquer sugestões ou dicas seriam apreciadas.

Atualizar: Acontece que eu tive dois problemas diferentes: um no lado do cliente e outro no lado do servidor. No lado do cliente, tive que garantir que meu objeto QFile permanecesse por aí durante a transação de rede. O método post () do QNetworkAccessManager retorna imediatamente, mas não é concluído imediatamente. Você precisa anexar um slot ao sinal final () do QNetworkAccessManager para determinar quando a postagem está realmente concluída. No meu caso, foi fácil manter o QFILE em torno de mais ou menos permanentemente, mas também anexei um slot ao sinal final () para verificar as respostas de erro do servidor.

Anexei o sinal ao slot assim:

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

Quando chegou a hora de enviar meu arquivo, escrevi o código da postagem como este (observe que o FishetedFile é um membro da minha classe e, portanto, não sai do escopo após este código):

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

O sinal finalizado (QNETWORKREPLY*) do QNetworkAccessManager desencadeia meu método pós -acabamento (QNETWORKREPLY*). Quando isso acontece, é seguro fechar o arquivo compactado e excluir o arquivo de dados representado pelo compactedfile. Para fins de depuração, também adicionei algumas instruções printf () para confirmar que a transação está concluída:

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();  
}  

Como o comprimido de arquivo não está fechado imediatamente e não sai do escopo, o QNETWORKACCESSMANAGER é capaz de levar o tempo que gosta de transmitir meu arquivo. Eventualmente, a transação está completa e meu método pós -acabamento () é chamado.

Meu outro problema (que também contribuiu para o comportamento que eu estava vendo onde a transação nunca foi concluída) foi que o código Python para o meu servidor da Web não estava em campo corretamente, mas isso está fora do escopo da minha pergunta original do QT.

Foi útil?

Solução

Você está criando compressedFile na pilha, e passando um ponteiro para o seu QNetworkRequest (e, finalmente, o seu QNetworkAccessManager). Assim que você deixar o método em que você está, compressedFile está saindo do escopo. Estou surpreso que não esteja colidindo com você, embora o comportamento seja indefinido.

Você precisa criar o QFile na pilha:

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

É claro que você precisará acompanhar isso e depois delete Uma vez que o post é concluído, ou defini -lo como filho do QNetworkReply para que seja destruído quando a resposta é destruída mais tarde:

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

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

Outras dicas

Você também pode agendar a exclusão automática de um arquivo alocado por heap usando sinais/slots

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, é muito mais localizado e encapsulado do que ter que manter seu arquivo na classe externa.

Observe que você deve remover o primeiro connect() Se você tem o seu postFinished(QNetworkReply*) slot, no qual você não deve esquecer de ligar reply->deleteLater() dentro dele para que o acima funcionasse.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top