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の動作を期待する方法と互換性がないようです。私の質問は次のとおりです。
- これは、QFileがWindowsで動作する方法に何らかの制限がありますか?
- QFileまたはQNetworkAccessManagerを使用してpost()を介してファイルをプッシュする他の方法はありますか?
- これはまったく機能しませんか?ファイルをアップロードする他の方法を見つける必要がありますか?
任意の提案やヒントをいただければ幸いです。
更新:クライアント側とサーバー側の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の質問の範囲外です。