6

Qt を使用して、クライアントとリモート サーバー間の永続的な接続を維持しようとしています。私のサーバー側は問題ありません。私はQtでクライアント側をやっています。ここではQNetworkAccessManager、get メソッド (メソッドの一部) でサーバーを要求するために使用しますQNetworkRequest。リクエストを送受信できるようになります。

しかし、しばらくしてから (約 2 分)、クライアントがサーバーに接続すると、リクエストが自動的に送信されて接続が閉じられます。QNetworkAccessManagerこの接続のタイムアウトを設定していると思います。両端間の永続的な接続を維持したい。

私のアプローチは正しいですか、そうでない場合、誰かが私を正しい道に導くことができますか?

4

2 に答える 2

4

この質問は興味深いので、いくつか調べてみましょう。キープアライブ タイムアウトを大きく設定して nginx サーバーをセットアップし、最も単純な Qt アプリケーションを作成しました。

QApplication a(argc, argv);
QNetworkAccessManager manager;
QNetworkRequest r(QUrl("http://myserver/"));
manager.get(r);
return a.exec();

また、次のコマンドを (Linux コンソールで) 使用して接続を監視し、問題が再現するかどうかを確認しました。

watch -n 1 netstat -n -A inet

Qt のソースをざっと見てみるQTcpSocketと、QHttpNetworkConnectionChannel::close. そこで、( Window → Views → Debugger logQt Creator で) デバッガー コンソールを開き、プロセスが一時停止している間にブレークポイントを追加しました。

bp QAbstractSocket::close

注: これは cdb (MS デバッガー) 用です。他のデバッガーには他のコマンドが必要です。別の注意: 私は Qt をデバッグ情報と共に使用していますが、このアプローチは Qt なしでは機能しない可能性があります。

2分間待った後、close()コールのバックトレースを取得しました!

QAbstractSocket::close  qabstractsocket.cpp 2587    0x13fe12600 
QHttpNetworkConnectionPrivate::~QHttpNetworkConnectionPrivate   qhttpnetworkconnection.cpp  110 0x13fe368c4 
QHttpNetworkConnectionPrivate::`scalar deleting destructor' untitled        0x13fe3db27 
QScopedPointerDeleter<QObjectData>::cleanup qscopedpointer.h    62  0x140356759 
QScopedPointer<QObjectData,QScopedPointerDeleter<QObjectData>>::~QScopedPointer<QObjectData,QScopedPointerDeleter<QObjectData>> qscopedpointer.h    99  0x140355700 
QObject::~QObject   qobject.cpp 863 0x14034b04f 
QHttpNetworkConnection::~QHttpNetworkConnection qhttpnetworkconnection.cpp  1148    0x13fe35fa2 
QNetworkAccessCachedHttpConnection::~QNetworkAccessCachedHttpConnection untitled        0x13fe1e644 
QNetworkAccessCachedHttpConnection::`scalar deleting destructor'    untitled        0x13fe1e6e7 
QNetworkAccessCachedHttpConnection::dispose qhttpthreaddelegate.cpp 170 0x13fe1e89e 
    QNetworkAccessCache::timerEvent qnetworkaccesscache.cpp 233 0x13fd99d07 
(next lines are not interesting)

このアクションを担当するクラスはQNetworkAccessCacheです。QNetworkAccessCache::Node::timestampタイマーを設定し、過去のオブジェクトが削除されるようにします。これらのオブジェクトは、HTTP 接続、FTP 接続、および資格情報です。

次に、 とはtimestamp?オブジェクトが解放されると、そのタイムスタンプが次の方法で計算されます。

node->timestamp = QDateTime::currentDateTime().addSecs(ExpiryTime);

そしてExpiryTime = 120、ハードコードされています。

関連するすべてのクラスはプライベートであり、これを防ぐ方法が見つかりませんでした。そのため、キープアライブ リクエストを 1 分ごとに送信する方が簡単です (少なくとも 1 分で十分安全であることがわかります)。別の方法として、Qt コードを書き直してカスタム バージョンをコンパイルします。

于 2015-04-20T17:32:58.357 に答える
1

定義上、2 分間のタイムアウト接続は永続的な資格があると言えます。つまり、永続的でない場合は、リクエストごとに再接続する必要があります. 2 分間という時間は、他のソフトウェアに比べてかなり余裕があります。しかし、非アクティブな状態が続くと最終的にタイムアウトするように設定されており、これは驚くべきことではありません。一部のソフトウェアではタイムアウト期間を変更できますが、Pavel の調査によると、Qt の場合はタイムアウトがハードコーディングされているようです。

幸いなことに、解決策は簡単です。接続を維持するために、約 1 分ごとにハートビート (単なるダミーの要求です。「ハートビート ネットワーク」と混同しないでください) を送信するようにタイマーを設定するだけです。接続を使用する前にタイマーを無効にし、接続が完了したらタイマーを再起動します。

于 2015-04-21T21:45:12.107 に答える