クライアントが CGI から切断されたことを検出できますか?

クライアントが CGI から切断されたことを検出できますか?

かなりリソースを消費する CGI があり、データの送信を開始するまでにかなり時間がかかります。せっかちな人が数回リロードすると、CGI がさらに実行されてロードされるケースや、クライアントがタイムアウトして接続が切断されても CGI が実行を続けるケースが数多く見られました。

これがいつ発生したかを検出する良い方法はありますか? CGI 自体の中にある必要すらありません (CGI 自体の中にある方がおそらく良いでしょう。制御できない別のプログラムに渡されるからです)。ただし、切断された接続を探すために定期的に実行される cron ジョブであれば可能です。

現在、Apache を使用していますが、これは非常に大きな問題なので、対処する機能 (または問題を監視できる機能) があれば、他の Web サーバーを実行してもかまいません。

答え1

通常、ユーザーへの書き戻しを開始するまで、接続が切断されたことを検出することはできません。そうしないと、プロセスはユーザー側からの接続の中断に気付かずに作業を続行します。この郵便受けPHP について話している場合でも関連があります。概念は同じであるはずです。

試すことができる可能性のあることは次のとおりです:

  1. 時間のかかる作業をバックグラウンドで実行します。ユーザーが CGI を要求したときに、通常のブロッキング呼び出しとしてタスクを実行しないでください。要求が処理中であることをユーザーに伝えるために、何かを返すだけです。もちろん、ビューを更新する方法を見つけるか、要求 ID または IP を使用してジョブの状態を確認するための別のページを提供する必要があります。
  2. できるだけ早くデータをクライアントに送り返し、送信に失敗した場合は終了します (接続が切断されたことを示します)。たとえば、ジョブの進行状況を数秒または数分ごとに送信できます。

現在実行中のジョブをデータベースに保存すると、リクエスト ID やクライアント IP アドレスを保存できます。これにより、同じリソースへの重複リクエストを検出して無視し、ユーザーに「リクエストは処理中です」と通知できます。

答え2

警告: この情報は古くなっている可能性があります。最後の段落を参照してください。

私も同じ問題を抱えていたことを覚えていますが、ナフ(解析ヘッダーなし) CGI スクリプト。

通常、Apache はスクリプトからすべてのヘッダーを収集し、ヘッダーの読み取りが完了すると、提供されていない標準ヘッダーでヘッダーを修正します。つまり、ヘッダーが終了しない限り、Apache はクライアントに何も送信しません。

nph スクリプトでは、すべてのヘッダーを提供する必要がありますが、Apache はそれらをすぐにクライアントに送信し、クライアントが切断されると CGI スクリプトに SIGPIPE を送信します。したがって、X-Slowly-Counting-Part-nnn: yesクライアントでのタイムアウトを防ぐために数秒ごとにヘッダーを送信でき、クライアントが接続を切断した場合に通知を受け取ることができます。

それでも問題は残ります。まずHTTPステータスを送信する必要がありますが、「Content-Length: 0」または「Content-Length: 1」を送信してコンテンツを送信せずに接続を閉じると、ファイルダウンローダーはすべきネットワーク エラーを想定し、それに応じて行動します。

おそらく、他のプログラムの出力をプロセスにパイプする必要がありますが、少なくとも Linux 上でシステム コールを使用する場合は、パフォーマンスに大きな影響は出ないはずですsendfile(2)

これらすべての問題は、私が少なくとも 10 年前にこれを使用しており、おそらく Apache 1.3 で使用していたが、Google で検索してもapache cgi nph役に立つ情報は何も得られなかったことです。したがって、その間に NPH 機能が削除された可能性がありますが、そうではないかもしれません。私はあまり熱心に調べなかったことを認めます。

答え3

古い質問ですが、私も同じ問題を抱えており、接続が確立されているかどうかを確認することで解決しました。

私の場合、サーバー上で1つのbashスクリプトを実行しています。環境変数はmod_cgiによってエクスポートされます。このソリューションは、CGIで実行されるすべてのプログラム/スクリプトで機能すると思います。

ss -nt state established "( sport = :$SERVER_PORT and dport = $REMOTE_ADDR:$REMOTE_PORT )" 2>/dev/null | grep -q "$REMOTE_ADDR:$REMOTE_PORT"
if [ "$?" -ne '0' ]; then
     # Client closed browser/connection
fi

関連情報