この記事では、http ブラウザーがアクティブに切断する方法と php がアクティブに切断する方法について説明します。興味のある友人は参照してください。
要約: このインシデントの原因は、開発中に発生した疑問によるものです。かつて、ブラウザ クライアントがアクティブに切断された後、サーバー側の PHP スクリプトがまだ実行されていることが判明したため、スクリプトを停止する方法がわかりませんでした。またある時は、PHP スクリプトを積極的に切断し、その後後続のスクリプトを実行し続ける必要があったため (時間のかかるタスク)、このブログが作成されました。
一般的に使用される LAMP の組み合わせでは、ブラウザが php スクリプトにアクセスし、スクリプトが実行を開始し、スクリプトがコンテンツを出力して実行を終了し、Apache が http に応答し、ブラウザが受信するものと考えられます。 http 応答すると、結果が表示されます。
特殊な状況を考えてみましょう。
1. ブラウザーは http リクエストを送信し、PHP は時間のかかるタスク (20 秒) を実行します (PHP の set_time_limit が 30 秒に設定されていると仮定します)。ユーザーが [ブラウザーを開く] をクリックしても、ブラウザーは応答しません。接続すると、PHP スクリプトは引き続き実行されます。 時間のかかるタスクが fib(25) の計算であるとします。時間のかかるタスクが実行されるたびに、ファイル ログが 10 回書き込まれます。 5 回目の実行時には、クライアントは積極的に切断して状況を観察します。
コードは以下の通りです:
<?phpfor ($i=0; $i < 10; $i++) { fib(25); setLog(date('H:i:s')); }function fib($n = 3){ if($n == 0){ return 1; } if($n == 1){ return 1; } return fib($n - 1) + fib($n -2); }function setLog( $massage, $path=''){ $log_path = empty($path)?'./log_'.date('Y-m-d').'.log':$path; $time = date('Y-m-d H:i:s'); $error_page = 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']; file_put_contents($log_path, "LOG TIME:".$time.PHP_EOL, FILE_APPEND); file_put_contents($log_path, "LOG URL:".$error_page.PHP_EOL, FILE_APPEND); if(is_array($massage)){ $massage = json_encode($massage); } file_put_contents($log_path, "LOG MESSAGE:".$massage.PHP_EOL.PHP_EOL, FILE_APPEND); }?>実行が5.44秒に達するとブラウザが切断されました。
ログには次のように表示されます: スクリプトは 10 サイクルを完了しました。
これは以前考えていたものと異なります;
2. PHP がコンテンツをクライアントに出力するときにクライアント接続が切断されるかどうかを判断するということをインターネットで見たので、テストを実行します。 : <phpfor ($i=0; $i < 10; $i++) {
fib(25); setLog(date('H:i:s')); echo "hello";
}
//这里省略了fib和setLog函数
?>
再度テストすると、結果は前回のテストと同じであることがわかります。理由: PHP がコンテンツをクライアントに出力するとき、次の 3 つのバッファリング段階があります:
バッファがいっぱいの場合のみクライアントに出力されます。これは実際にはバックエンドがコンテンツをフロントエンドに時々出力するという原則。もちろん、バッファがいっぱいでない場合に、クライアントへの出力を制御することもできます。
<?php$re = "";for($i=0; $i < 10000; $i++){ $re .= "aa";
}for ($i=0; $i < 10; $i++) {
fib(25);
setLog(date('H:i:s')); echo $re;
}//这里省略了fib和setLog函数?>
今回もテストすると、前のデモではなく、しばらくしてからブラウザがいくつかの応答を受け取ることがわかります。これにはスクリプトが必要です。コンテンツは、完全に実行された後にのみクライアントに出力されます。同時に、この時点でクライアント接続が閉じられ、サーバーがコンテンツをクライアントに再度出力すると、この時点でクライアント接続が切断されたことが確認されます。これが私たちが望むテスト結果です。
4. 再度テストコードを修正します。今回は一度に大きな内容を出力するのではなく、バッファからクライアントに出力しきれない内容を意図的に操作します。クライアントに事前に出力します。
テストコード:
for ($i=0; $i < 10; $i++) { fib(25); setLog(date('H:i:s')); echo "hello " . date('H:i:s') . "<br>"; ob_flush(); flush(); } //这里省略了fib和setLog函数
connection,当客户端收到响应头connection的值为close或者keep-alive,决定关闭当前tcp连接或者继续使用当前连接作下一次请求;
测试发现,当只指定conetent-length的时候也能达到php主动断开连接;
其实说是php主动断开连接,其实是php通知客户端主动断开的连接;
示例代码:
<?phpecho "hello world"; test();for ($i=0; $i < 10; $i++) { fib(25); setLog(date('H:i:s')); }function test(){ $size = ob_get_length(); header("content-length:" . $size); //header("connection:close"); ob_flush(); flush(); }//这里省略了fib和setLog函数?>
ba33df4ef3efea3726e09756c08771e7
以上がhttpブラウザはアクティブに切断し、phpはアクティブに切断しますの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。