7

Qtアプリケーションで問題が発生しています。特にQNetworkAccessManagerクラスを使用します。QNetworkAccessManagerのpost()メソッドを使用して、バイナリファイルの単純なHTTPアップロードを実行しようとしています。ドキュメントには、post()へのQIODeviceへのポインターを指定でき、クラスはQIODeviceで見つかったデータを送信すると記載されています。これは、post()にQFileへのポインターを与えることができるはずであることを私に示唆しています。例えば:

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

これを開発しているWindowsシステムで発生しているように見えるのは、QtアプリケーションがQFileからデータをプッシュした後、要求を完了しないことです。ファイルからさらにデータが表示されるのを待っているようです。アプリケーションを手動で強制終了するまで、POSTリクエストは「クローズ」されません。強制終了すると、ファイル全体がサーバー側に表示されます。

いくつかのデバッグと調査から、これは、ファイルの最後に到達したときにQFileのread()操作が-1を返さないために発生していると思います。QNetworkAccessManagerは、read()から-1を取得するまで、QIODeviceから読み取ろうとしていると思います。取得した時点で、データがなくなったと見なして要求を閉じます。read()からゼロの戻りコードを取得し続ける場合、QNetworkAccessManagerは、さらに多くのデータが来る可能性があると想定するため、その仮想データを待機し続けます。

いくつかのテストコードで、ファイルの最後まで読み取った後、QFileのread()操作がゼロを返すことを確認しました。これは、QNetworkAccessManagerのpost()メソッドがQIODeviceの動作を期待する方法と互換性がないようです。私の質問は次のとおりです。

  1. これは、QFileがWindowsで動作する方法に何らかの制限がありますか?
  2. QFileまたはQNetworkAccessManagerを使用してpost()を介してファイルをプッシュする他の方法はありますか?
  3. これはまったく機能しませんか?ファイルをアップロードする他の方法を見つける必要がありますか?

任意の提案やヒントをいただければ幸いです。

更新:クライアント側とサーバー側の2つの異なる問題が発生したことが判明しました。クライアント側では、ネットワークトランザクションの間、QFileオブジェクトが存在することを確認する必要がありました。QNetworkAccessManagerのpost()メソッドはすぐに戻りますが、実際にはすぐには終了しません。POSTが実際に終了するタイミングを決定するには、QNetworkAccessManagerのfinished()シグナルにスロットを接続する必要があります。私の場合、QFileをほぼ恒久的に維持するのは簡単でしたが、サーバーからのエラー応答をチェックするために、finished()シグナルにスロットを接続しました。

私はこのように信号をスロットに取り付けました:

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

ファイルを送信するときは、次のような郵便番号を記述しました(compressedFileは私のクラスのメンバーであるため、このコードの後でスコープから外れることはありません)。

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

QNetworkAccessManagerからのfinished(QNetworkReply *)シグナルは、postFinished(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は、ファイルの送信に必要なだけの時間をかけることができます。最終的にトランザクションが完了し、postFinished()メソッドが呼び出されます。

私の他の問題(トランザクションが完了しなかった場所で見た動作にも影響しました)は、WebサーバーのPythonコードがPOSTを正しく処理していなかったことですが、これは元のQtの質問の範囲外です。

4

2 に答える 2

8

スタック上に作成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);
于 2010-05-11T06:29:32.290 に答える
3

シグナル/スロットを使用して、ヒープに割り当てられたファイルの自動削除をスケジュールすることもできます

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

于 2010-07-14T07:45:50.453 に答える