Pregunta

Estoy teniendo algunos problemas con una aplicación Qt; específicamente con la clase QNetworkAccessManager. Estoy intentando realizar una simple carga HTTP de un archivo binario utilizando el método POST () de la QNetworkAccessManager. La documentación que puedo dar un puntero a una QIODevice a post (), y que la clase va a transmitir los datos encontrados en el QIODevice. Esto me sugiere que debería ser capaz de dar post () un puntero a una QFile. Por ejemplo:

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

Lo que parece ocurrir en el sistema Windows donde estoy desarrollando esto es que mi aplicación Qt empuja los datos de la QFile, pero luego no completar la solicitud; parece estar sentado allí a la espera de más datos para aparecer a partir del archivo. La solicitud post no es "cerrado" hasta que mato manualmente la aplicación, momento en el que el conjunto de programas de archivos hasta en mi extremo del servidor.

A partir de cierta depuración y la investigación, creo que esto está sucediendo porque la operación de lectura () de QFile no devuelve -1 cuando se llega al final del archivo. Creo que QNetworkAccessManager está intentando leer desde el QIODevice hasta que se consigue un -1 de lectura (), en cuyo punto se asume que no hay más datos y cierra la solicitud. Si cada vez es un código de retorno cero de lectura (), QNetworkAccessManager asume que puede haber más datos que viene, y por lo que mantiene a la espera de que los datos hipotéticos.

He confirmado con un poco de código de prueba de que la operación de lectura () de QFile simplemente devuelve cero después de haber leído al final del archivo. Esto parece ser incompatible con la forma en que el método post () de QNetworkAccessManager espera una QIODevice comportarse. Mis preguntas son:

  1. ¿Es esto algún tipo de limitación con la forma en que funciona bajo Windows QFile?
  2. ¿Hay alguna otra manera que debería estar utilizando ya sea QFile o QNetworkAccessManager para empujar un archivo a través de correos ()?
  3. ¿Está esto no va a trabajar en absoluto, y voy a tener que encontrar alguna otra manera de subir mi archivo?

Cualquier sugerencia o consejos sería apreciada.

Actualización: Resulta que tuve dos problemas diferentes: uno en el lado del cliente y uno en el lado del servidor. En el lado del cliente, tenía que asegurarse de que mi objeto QFile se mantuvo en torno a la duración de la operación de la red. El método post () de QNetworkAccessManager vuelve inmediatamente, pero no es en realidad terminó inmediatamente. Es necesario adjuntar una ranura a la señal de acabado () de QNetworkAccessManager para determinar cuando el mensaje es en realidad terminó. En mi caso fue bastante fácil de mantener el QFile alrededor de más o menos permanente, pero también me une una ranura a la señal terminado () con el fin de comprobar si las respuestas de error del servidor.

I adjunta la señal a la ranura de esta manera:

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

A la hora de enviar mi archivo, que escribió el código post como este (nota que compressedFile es un miembro de mi clase y por lo tanto no salir del alcance después de este código):

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

La señal terminado (QNetworkReply *) de QNetworkAccessManager desencadena mi método postFinished (QNetworkReply *). Cuando esto sucede, es seguro para que cierre compressedFile y eliminar el archivo de datos representada por compressedFile. Para propósitos de depuración También he añadido unos cuantos printf () declaraciones para confirmar que la transacción es completa:

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

Desde compressedFile no se cierra inmediatamente y no va más allá del ámbito, la QNetworkAccessManager es capaz de tomar tanto tiempo como le gusta transmitir mi archivo. Eventualmente se complete la transacción y el método de mi postFinished () es llamado.

Mi otro problema (lo que también contribuyó a la conducta que estaba viendo cuando la transacción nunca se completó) fue que el código Python para mi servidor web no se alineará el POST correctamente, pero que está fuera del alcance de mi pregunta original Qt.

¿Fue útil?

Solución

Estás creando compressedFile en la pila, y pasar un puntero a ella a su QNetworkRequest (y en última instancia su QNetworkAccessManager). Tan pronto como salga el método que se encuentre, compressedFile va fuera de alcance. Me sorprende que no está rompiendo en vosotros, el comportamiento no está definido.

Es necesario crear el QFile en el montón:

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

Usted, por supuesto, la necesidad de hacer un seguimiento de ella y luego delete que una vez que el mensaje ha completado, o establecerlo como el hijo de la QNetworkReply de modo que se destruye cuando la respuesta se destruye más tarde:

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

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

Otros consejos

También puede programar el borrado automático de un archivo montón asignados utilizando señales / ranuras

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

En mi humilde opinión, es mucho más localizada y encapsulado de tener que mantener alrededor de su archivo en la clase externa.

Tenga en cuenta que debe quitar el primer connect() si usted tiene su ranura postFinished(QNetworkReply*), en el que a continuación, no hay que olvidar que llamar reply->deleteLater() en su interior para el anterior para el trabajo.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top