2013-05-01 3 views
4

서버에서 클라이언트로 정기적 인 업데이트를 보내려고합니다. 그 때문에 나는 server-sent 이벤트를 사용했다. 나는 아래의 코드를 붙여 해요 :HTML5 서버 전송 이벤트의 시간 간격 설정

클라이언트 측

얻기 서버 업데이트

<script> 
if(typeof(EventSource)!="undefined") 
{ 
    var source=new EventSource("demo_see.php"); 
    source.onmessage=function(event) 
    { 
     document.getElementById("result").innerHTML=event.data + "<br>"; 
    } 
} 
else 
{ 
    document.getElementById("result").innerHTML="Sorry, your browser does not support server-sent events..."; 
} 
</script> 
</body> 
</html> 

서버 측

<?php 
    header('Content-Type: text/event-stream'); 
    header('Cache-Control: no-cache'); 
    $x=rand(0,1000); 
    echo "data:{$x}\n\n"; 
    flush(); 
?> 

코드는 잘 작동하지만, 센 모든 3 seconds에 ds 업데이트 밀리 초 단위로 업데이트를 보내려고합니다. flush() 이후에 sleep(1)을 시도했지만 간격을 1 초 더 늘립니다. 누구든지 아이디어를 어떻게 성취 할 수 있습니까?

또한 서버 전송 이벤트를 사용하여 이미지를 보낼 수 있습니까?

브라우저는 각각의 연결이 종료 약 삼초 후 소스에 다시 연결을 시도

그래서 하나 개의 방법 : here을 설명

답변

5

이 동작 (메시지 3 초마다)에 대한 이유는 100 밀리 초마다 메시지를 수신하면 다시 연결 시간이 변경됩니다. (PHP의 경우)

echo "retry: 100\n\n"; 

우아하지만 더 좋은 접근법은 매 반복마다 100 밀리 초 동안 sleep하는 PHP의 무한 루프가 될 것입니다. 좋은 예 here 그냥 밀리 초 지원하기 위해 sleep()usleep()에 변경,이하십시오 sleep 또는 usleep으로 무한 루프에서 PHP 스크립트를 실행 위의 설명에서 언급 한 바와 같이

while (1) { 
    $x=rand(0,1000); 
    echo "data:{$x}\n\n"; 
    flush(); 
    usleep(100000); //1000000 = 1 seconds 
} 
+1

이 답변이 두 번 upvoted되었습니다 약간 놀랍습니다. 그것은'usleep'으로 무한 루프에서 PHP 스크립트를 실행할 것을 제안합니다. 예를 들어 1000 개의 브라우저가 서버와 연결되어 서버 전송 이벤트를 요구하면 어떻게 될지 상상해보십시오. PHP 스크립트의 올바른 방법은 조용히 작업을 끝내고 종료하는 것입니다. 브라우저가 단순히 이벤트의 완료를 인식하지 못하고 서버 CPU가 멀리 떨어져 버리는 것은 실패합니다 .... 서버가 이벤트를 보내면 항상 브라우저가 다시 연결되며 빈도는 재시도 간격에 의해 결정됩니다. – DroidOS

+1

@DroidOS 고마워, 나는 그 사실을 몰랐다. 더 나은 대답을 쓸 수 있다면 좋을 것입니다. (내 대답을 편집하려면 PHP 익숙하지 않음) –

+0

실제로 새로운 대답은 필요하지 않습니다. PHP 스크립트를 통해 이벤트 스트림을 다시 보내고 정상적으로 끝내기 만하면됩니다. 당연히 이벤트 스트림은'retry : x \ n \ n' 행을 포함 할 수 있습니다. 여기서 x는 밀리 초입니다. 나머지는 브라우저에서 처리합니다. 모질라가 SSE를 위해 그러한 결함있는 PHP 코드를 제안했다는 사실에 놀랐습니다. 이 예제를 따르는 경우 머지 않아 서버를 최대한 활용할 수 있습니다. – DroidOS

8

하는 것은 두 가지 이유

에 적합하지 않습니다
  • 브라우저에서 이벤트 데이터를 볼 수 없습니다 (스크립트가 실행되는 동안 연결이 먼저 닫힐 때까지 기다리는 것으로 추정 됨). SSE에 대한 초기 브라우저 구현이 이것을 허용했지만 더 이상 그렇지 않습니다.
  • 브라우저 측에서 작동하더라도 PHP.ini time_out 설정이 시작될 때까지 지나치게 길게 실행되는 PHP 스크립트가있는 문제에 여전히 직면 할 수 있습니다. 이런 일이 한두 번 발생하면 괜찮습니다. 서버에서 동일한 SSE를 동시에 찾는 수천 개의 브라우저가 있으면 서버가 다운됩니다.

정상적인 방법은 PHP 스크립트가 이벤트 스트림 데이터로 응답 한 다음 일반적으로 정상적으로 종료되도록하는 것입니다. 브라우저가 다시 시도 할시기를 제어하려면 retry 값 (밀리 초 단위)을 제공하십시오.서버를 폴링 할 때이 방법이에

는 당신이 얻을 무엇 : 다음은이 완전성의 이익에 늦게하지만 그럼에도 불구하고 비트입니다 원래의 질문에 대한 답변으로 몇 가지 예제 코드

function yourEventData(&$retry) 
{ 
//do your own stuff here and return your event data. 
//You might want to return a $retry value (milliseconds) 
//so the browser knows when to try again (not the default 3000 ms) 
} 

header('Content-Type: text/event-stream'); 
header('Cache-Control: no-cache'); 
header('Access-Control-Allow-Origin: *');//optional 

$data = yourEventData($retry); 

echo "data:{$str}\n\nretry:{$retry}\n\n"; 

입니다 그냥 데이터. 그 후에 당신이하는 일은 전적으로 당신에게 달린 것입니다. 이러한 데이터를 이미지로 처리하고 웹 페이지에 표시된 이미지를 업데이트하려는 경우 간단하게 수행 할 것입니다.

너무 많은 원칙이 있습니다. 나는 retry이 밀리 초 단위로 돌아가는 것을 잊어 버렸습니다. 예를 들어, retry:5\n\n은 놀랍게도 여전히 효과가있었습니다. 그러나 SSE를 사용하여 100ms 간격으로 브라우저 측 이미지를 업데이트하는 것을 주저합니다. 보다 일반적인 사용법은 다음 줄을 따라야합니다.

  • 사용자가 서버에서 작업을 요청합니다. 이 작업은 이 다른 작업 뒤에 대기열이 있거나 실행에 많은 시간이 걸릴 수 있습니다 (예 : PDF 또는 Excel 스프레드 시트 작성 및 다시 보내기)
  • 피드백없이 사용자를 대기시키는 대신 시간 초과를 위험에 빠뜨릴 수 있습니다. 브라우저가 ETA로 작업 완료를 알리는 SSE를 실행하고 retry 값이 설정되어 브라우저가 결과를 다시 볼 때를 알 수 있습니다.
  • ETA를 브라우저를 다시 볼 것이다 ETA의 끝에서 몇 가지 의견을
  • 을 사용자에게 제공하는 데 사용됩니다 어떤 이유로 작업이없는 경우
  • (브라우저는 아무것도 할 필요가 있으므로 자동으로 수행) 서버에 의해 완료되면 이벤트 스트림에서 반환된다는 것을 나타내야합니다. data{"code":-1}\n\n 브라우저 측 코드가 정상적으로 상황을 처리 할 수 ​​있습니다.

주식 시세, 뉴스 헤드 라인 업데이트 등의 다른 사용 시나리오가 있습니다. 100ms 간격으로 이미지를 업데이트하는 것은 기술의 오용과 같이 완전히 개인적인 시각을 나타냅니다.

+0

매우 유익한 대답이지만, PHP는 자고있는 동안이 스크립트에서 CPU에 거의 아무런 부하가 없어야한다고 생각합니다. 브라우저가 매 100ms마다 나오고 PHP 서버 시간 제한을 사용하지 않고 잠자기 상태가되면 새 연결의로드 사이에 아무런 비교가 없습니다 – Fritz

+0

그래서 PHP 서버가 무한 루프를 사용할 때 503 오류를 반환하는 이유는 무엇입니까? 데이터가 업데이트되면 중단됩니다. - 더 이상 지원되지 않습니다. :( – Soaku

0

나는 대답이 일 수 있다고 생각합니다. 질문에 올바르게 대답하지만 (1 초 간격을 설정하는 방법) 무한 루프가 일반적으로 나쁜 접근 방법이라는 것은 사실이 아닙니다.

SSE는 실제로 일정 시간 간격으로 업데이트가 없는지 여부를 지속적으로 검사하는 Ajax 폴링에 반대되는 업데이트가있을 때 서버에서 업데이트를 가져 오는 데 사용됩니다. 이는 서버 측 스크립트가 항상 실행되도록하는 무한 루프를 통해 수행 할 수 있으며, 변경 사항이있을 경우에만 업데이트를 확인하고 에코합니다.

그것은 사실이 아니다입니다 : 해당 스크립트가 계속 실행되는 동안

브라우저는 모든 이벤트 데이터를 볼 수 없습니다.

당신은 서버에서 스크립트를 실행하고 여전히 같은 스크립트 실행 종료하지 브라우저로 업데이트를 보낼 수 있습니다 스크립트를 종료합니다 무한 루프없이 매개 변수를 다시 시도 보내

while (true) { 
    echo "data: test\n\n"; 
    flush(); 
    ob_flush(); 
    sleep(1); 
} 

그 일을 그런 다음 스크립트를 다시 시작하고 종료하십시오. 다시 시작하십시오. 이것은 Ajax 폴링이 업데이트가 없는지 여부를 확인하는 것과 비슷하며 SSE의 작동 방법이 아닙니다. 물론 수락 된 답변에 나열된 것처럼이 접근법이 적절한 상황이 있습니다 (예 : 서버에서 PDF를 작성하고 완료 될 때 클라이언트에 알리기를 기다리는 경우).

무한 루프 기술을 사용하면 서버에서 스크립트가 계속 실행되므로 각 인스턴스에 대한 스크립트 인스턴스가 있고 서버 과부하로 이어질 수 있으므로 많은 사용자를주의해야합니다. 반면 SSE가없는 웹 사이트에서 갑자기 많은 사용자를 얻거나 SSE 대신 웹 소켓을 사용하는 간단한 시나리오에서도 동일한 문제가 발생합니다. 모든 것에는 한계가 있습니다.

또 하나주의해야 할 점은 루프에 넣는 것입니다. 예를 들어, 매초마다 실행되는 루프에 데이터베이스 쿼리를 두는 것을 권장하지 않습니다. 그 이유는 데이터베이스가 과부하 위험에 처하게되기 때문입니다. 이 경우에는 일종의 캐시 (Redis 또는 간단한 텍스트 파일)를 사용하는 것이 좋습니다.