>  기사  >  백엔드 개발  >  http 브라우저가 적극적으로 연결을 끊고 php가 적극적으로 연결을 끊습니다.

http 브라우저가 적극적으로 연결을 끊고 php가 적극적으로 연결을 끊습니다.

不言
不言원래의
2018-04-26 14:41:215028검색

이 기사에서는 http 브라우저가 어떻게 적극적으로 연결을 끊고 php가 어떻게 적극적으로 연결을 끊는지 알려드립니다. 관심 있는 친구들은 한 번 살펴보세요

요약: 이 사건의 원인은 개발 중에 발생한 의심 때문입니다. 한번은 브라우저 클라이언트의 연결이 끊어진 후 서버 측 PHP 스크립트가 여전히 실행 중인 것으로 확인되어 스크립트를 중지하는 방법을 몰랐습니다. 또 한 번은 PHP 스크립트의 연결을 적극적으로 끊고 후속 스크립트를 계속 실행해야 하는 경우(시간이 많이 걸리는 작업)가 있어서 이 블로그가 만들어졌습니다.

1. 브라우저가 적극적으로 연결을 끊습니다

  일반적으로 사용되는 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(&#39;H:i:s&#39;));
}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=&#39;&#39;){
    $log_path = empty($path)?&#39;./log_&#39;.date(&#39;Y-m-d&#39;).&#39;.log&#39;:$path;    $time = date(&#39;Y-m-d H:i:s&#39;);    $error_page = &#39;http://&#39; . $_SERVER[&#39;HTTP_HOST&#39;] . $_SERVER[&#39;REQUEST_URI&#39;];
    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(&#39;H:i:s&#39;));    echo "hello";
}

//这里省略了fib和setLog函数
?>
 다시 테스트해본 결과 지난 테스트와 동일한지 확인하세요. 이유: PHP가 클라이언트에 콘텐츠를 출력할 때 다음과 같은 세 가지 버퍼링 단계가 있습니다.

 PHP 버퍼 => 웹 서버 버퍼 => 브라우저 버퍼

  버퍼가 가득 찬 경우에만 클라이언트에 출력됩니다. 이는 실제로 백엔드가 가끔씩 프런트엔드로 콘텐츠를 출력하는 원리입니다. 물론 버퍼가 가득 차지 않을 때 클라이언트에 대한 출력을 제어할 수도 있습니다.

3. 출력 클라이언트의 콘텐츠를 충분히 크게 만들기 위해 테스트 코드를 다시 수정합니다.

<?php$re = "";for($i=0; $i < 10000; $i++){    $re .= "aa";
}for ($i=0; $i < 10; $i++) { 
    fib(25);
    setLog(date(&#39;H:i:s&#39;));    echo $re;
}//这里省略了fib和setLog函数?>
  이번에 다시 테스트하면 브라우저가 이전 데모 대신 잠시 후에 일부 응답을 받게 될 것입니다. 스크립트가 필요합니다. 내용은 완전히 실행된 후에야 클라이언트에 출력됩니다. 동시에 클라이언트 연결이 닫힙니다. 서버가 클라이언트에 콘텐츠를 다시 출력하면 클라이언트 연결이 끊어졌는지 확인하고 스크립트 실행이 중지됩니다. 이것이 우리가 원하는 테스트 결과입니다.

4. 테스트 코드를 다시 수정합니다. 이번에는 큰 내용을 한번에 출력하는 것이 아니라 의도적으로 버퍼의 내용을 조작하여 버퍼에서 클라이언트로 출력하기에는 부족한 내용이 출력되도록 합니다. 클라이언트에 미리 출력합니다.

테스트 코드:

for ($i=0; $i < 10; $i++) { 
    fib(25);    setLog(date(&#39;H:i:s&#39;));    echo "hello " . date(&#39;H:i:s&#39;) . "<br>";
    ob_flush();
    flush();
}
//这里省略了fib和setLog函数

요약:

    원칙적으로 클라이언트의 연결이 끊어지면 PHP 스크립트의 실행이 중지됩니다.
  • 그러나 전제는 PHP가 클라이언트의 연결이 끊어지는 방법을 알고 있다는 것입니다. (웹 서버 버퍼가 아닌 PHP 버퍼가 아닌) 콘텐츠를 출력합니다. PHP는 클라이언트 연결이 중단되었음을 인식하고 실행을 중지합니다.
  • PHP가 클라이언트에 콘텐츠를 출력하는 방법에는 두 가지가 있습니다. 첫 번째는 콘텐츠를 버퍼에 채우고 자동으로 클라이언트에 보내는 것입니다. 두 번째는 버퍼 콘텐츠를 클라이언트에 적극적으로 플러시하는 플러시 함수인 ob_flush를 사용하는 것입니다. php .ini에서 수행하거나 호스트 아파치 구성 파일에서 구성하거나 스크립트의 set_time_limt 함수를 통해 설정할 수 있는 내부 스크립트 타이머
  • 클라이언트가 적극적으로 연결을 끊고 PHP 스크립트 실행이 중지되지 않으면
  • php 스크립트가ignore_user_abort(true);를 설정하면 클라이언트 연결이 끊어지고 PHP가 클라이언트에 콘텐츠를 출력하고 클라이언트 연결이 끊어진 것을 알고 있더라도 스크립트 실행은
  • PHP 내부에서 유지되는 연결 상태는 Connection_status 함수의 반환 값을 통해 확인할 수 있습니다. 0: 정상; 2: 변경된 상태를 감지하려면; 콘텐츠가 알려지기 전에 클라이언트에 출력하는 PHP 스크립트, 그렇지 않으면 항상 모두 0입니다.
  • 클라이언트 연결이 끊어졌는지(connection_aborted) 여부도 감지할 수 있는 함수도 있습니다. 0은 정상입니다. , 1개의 연결이 끊어졌습니다.
  • 이상한 문제는 클라이언트 연결이 끊어지고 PHP 스크립트가 두 번 출력되면 상태 비트가 1이 된다는 것입니다.
  • 두 번째로, PHP 서버가 적극적으로 연결을 끊습니다
  •  http 응답 헤더의 content-length 및 연결 필드 의미는 다음과 같습니다.

클라이언트가 응답 헤더 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(&#39;H:i:s&#39;));
    }function test(){
        $size = ob_get_length();
        header("content-length:" . $size);    //header("connection:close");
        ob_flush();
        flush();
    }//这里省略了fib和setLog函数?>



    ba33df4ef3efea3726e09756c08771e7



    위 내용은 http 브라우저가 적극적으로 연결을 끊고 php가 적극적으로 연결을 끊습니다.의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

    성명:
    본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.