이 기사에서는 http 브라우저가 어떻게 적극적으로 연결을 끊고 php가 어떻게 적극적으로 연결을 끊는지 알려드립니다. 관심 있는 친구들은 한 번 살펴보세요
요약: 이 사건의 원인은 개발 중에 발생한 의심 때문입니다. 한번은 브라우저 클라이언트의 연결이 끊어진 후 서버 측 PHP 스크립트가 여전히 실행 중인 것으로 확인되어 스크립트를 중지하는 방법을 몰랐습니다. 또 한 번은 PHP 스크립트의 연결을 적극적으로 끊고 후속 스크립트를 계속 실행해야 하는 경우(시간이 많이 걸리는 작업)가 있어서 이 블로그가 만들어졌습니다.
일반적으로 사용되는 LAMP 조합에서 우리는 브라우저가 PHP 스크립트에 액세스하고, 스크립트가 실행을 시작하고, 스크립트가 콘텐츠를 출력하고, 실행을 종료하고, Apache가 http에 응답하고, 브라우저가 수신을 받는다고 믿습니다. http 응답으로 결과가 표시됩니다.
특수한 상황을 생각해 봅시다.
1. 브라우저는 http 요청을 보내고 PHP는 시간이 많이 소요되는 작업(20초)을 수행합니다(PHP의 set_time_limit가 30초로 설정되어 있다고 가정). 이 기간 동안 브라우저는 브라우저를 클릭하면 응답하지 않습니다. 연결하면 PHP 스크립트가 계속 실행됩니다. 시간이 많이 걸리는 작업이 fib(25) 계산이라고 가정하면, 브라우저 테스트 응답은 1.15초가 걸립니다. 시간이 많이 걸리는 작업이 실행될 때마다 파일 로그가 10번 실행됩니다. 다섯 번째 실행 시 클라이언트는 적극적으로 연결을 끊고 상황을 관찰합니다.
코드는 다음과 같습니다.
<?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가 클라이언트에 콘텐츠를 출력할 때 다음과 같은 세 가지 버퍼링 단계가 있습니다.
버퍼가 가득 찬 경우에만 클라이언트에 출력됩니다. 이는 실제로 백엔드가 가끔씩 프런트엔드로 콘텐츠를 출력하는 원리입니다. 물론 버퍼가 가득 차지 않을 때 클라이언트에 대한 출력을 제어할 수도 있습니다.
<?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函数
http 응답 헤더의 content-length 및 연결 필드 의미는 다음과 같습니다.
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 중국어 웹사이트의 기타 관련 기사를 참조하세요!