서버에서 보낸 이벤트 및 PHP-서버에서 이벤트를 트리거하는 것은 무엇입니까?


93

모두,

HTML5 Rocks에는 SSE (Server-sent Events)에 대한 멋진 초보자 자습서가 있습니다.

http://www.html5rocks.com/en/tutorials/eventsource/basics/

그러나 중요한 개념을 이해하지 못합니다. 서버에서 메시지를 보내는 이벤트를 트리거하는 것은 무엇입니까?

즉, HTML5 예제에서 서버는 타임 스탬프를 한 번만 보냅니다 .

<?php
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache'); // recommended to prevent caching of event data.
function sendMsg($id, $msg) {
  echo "id: $id" . PHP_EOL;
  echo "data: $msg" . PHP_EOL;
  echo PHP_EOL;
  ob_flush();
  flush();
}
$serverTime = time();
sendMsg($serverTime, 'server time: ' . date("h:i:s", time()));

예를 들어 페이스 북 스타일의 "벽"이나 주식 시세표와 같은 실제 예제를 만들고 있다면, 서버가 데이터의 일부가 변경 될 때마다 새 메시지를 "푸시"하는 방법은 어떻게 작동합니까?

다시 말해 ... PHP 스크립트에는 데이터의 변경 사항을 확인한 다음 찾을 때마다 메시지를 보내는 루프가 지속적으로 실행됩니까? 그렇다면 해당 프로세스를 언제 끝낼 지 어떻게 알 수 있습니까?

아니면-PHP 스크립트가 단순히 메시지를 보낸 다음 종료합니까 (HTML5Rocks 예제의 경우처럼)? 그렇다면-어떻게 지속적인 업데이트를 받습니까? 브라우저가 단순히 정기적으로 PHP 페이지를 폴링합니까? 그렇다면 어떻게 "서버에서 보낸 이벤트"입니까? AJAX를 사용하여 정기적으로 PHP 페이지를 호출하는 JavaScript에서 setInterval 함수를 작성하는 것과 어떻게 다른가요?

죄송합니다. 이것은 아마도 믿을 수 없을 정도로 순진한 질문 일 것입니다. 그러나 내가 찾은 예 중 어느 것도 이것을 명확하게하지 않습니다.

[최신 정보]

내 질문이 제대로 표현되지 않았기 때문에 여기에 몇 가지 설명이 있습니다.

Apple 주식의 가장 최근 가격을 표시해야하는 웹 페이지가 있다고 가정 해 보겠습니다.

사용자가 처음 페이지를 열면 페이지는 내 "스트림"의 URL을 사용하여 EventSource를 만듭니다.

var source = new EventSource('stream.php');

내 질문은 이것이다- "stream.php"는 어떻게 작동해야합니까?

이렇게? (의사 코드) :

<?php
    header('Content-Type: text/event-stream');
    header('Cache-Control: no-cache'); // recommended to prevent caching of event data.
    function sendMsg($msg) {
        echo "data: $msg" . PHP_EOL;
        echo PHP_EOL;
        flush();
    }

    while (some condition) {
        // check whether Apple's stock price has changed
        // e.g., by querying a database, or calling a web service
        // if it HAS changed, sendMsg with new price to client
        // otherwise, do nothing (until next loop)
        sleep (n) // wait n seconds until checking again
    }
?>

즉, "stream.php"는 클라이언트가 "연결"되어있는 한 계속 열려 있습니까?

그렇다면 stream.php동시 사용자 수만큼 스레드가 실행 되고 있음을 의미 합니까? 그렇다면 원격으로 실행 가능합니까, 아니면 애플리케이션을 구축하는 적절한 방법입니까? 그리고 인스턴스를 언제 끝낼 수 있는지 어떻게 알 수 stream.php있습니까?

내 순진한 인상은이 경우 PHP 이러한 종류의 서버에 적합한 기술 이 아니라는 것입니다. 그러나 지금까지 본 모든 데모는 PHP가 이것에 적합하다는 것을 암시합니다. 그래서 내가 혼란스러워합니다.


개발자가 스스로 코딩해야하는 부분입니다. 데이터를 획득하는 수단은 WebSocket을 / 롱 폴링 등 그러나 트릭 비아있는 어떤 이벤트를 트리거한다. 개인적으로, 나는 몇 가지 접근 방식을 실험하고 내가 좋아하는 것을 하나의 접근 방법 (하지만 아니 었 한 것을 MySQL을 트리거 할 때마다 뭔가가 특정 테이블에 삽입 된 콘솔 프로그램 제작 된 안전 장치). 콘솔 프로그램은 변경 / 삽입 된 레코드에 대한 정보를 수신하고 WebSocket을 통해 해당 사용자에게 알림을 보냅니다. 기본적으로 메시지를 보내기 위해 대기중인 PHP 데몬이 있습니다.
NB

이 하나의 문제는, SSE는 IE에서 지원되지 않습니다 : - / 나는 또한이 읽을 것 prodigyproductionsllc.com/articles/programming/javascript/...을 나는 그가 너무 많은 아이들의 문제이지만 같은 전반적인 모습을 피하기 위해 포트를 사용하여 생각 그의 권장 사항은 SSE를 피하는 것입니다. 가치보다 훨씬 더 많은 문제인 것 같습니다, IMO.
PJ Brunet 2013

현재 IE11 또는 Android 브라우저에서 지원되지 않음 caniuse.com/eventsource
PJ Brunet

1
만약 SSE PHP 코드를 필요로하는 몇 가지 중 하나 : github.com/shahzadthathal/server-sent-events-php-example
무하마드 Shahzad

4
나는 같은 질문이 있었고 서버에서 이벤트를 트리거하는 것이 무엇을 의미하는지 깊이 이해하고 있다고 생각 합니다 . 의 객체를 만들면 EventSource('stream.php')클라이언트 stream.php는 ajax로 호출하는 것과 같은 연결을 엽니 다 . 연결은 서버 측 코드를 트리거하고 서버 측 코드에 할 말이있는 한 연결을 열어 둡니다. 그런 다음 연결이 닫히고 잠시 후 (크롬에서 3 초) 클라이언트가 연결을 다시 열어 stream.php파일을 다시 트리거합니다 .
Ahmad Maleki

답변:


29

"..."stream.php "는 클라이언트가"연결 "되어있는 한 계속 열려 있습니까?"

예, 의사 코드는 합리적인 접근 방식입니다.

"그리고 stream.php의 인스턴스를 언제 끝낼 수 있는지 어떻게 알 수 있습니까?"

가장 일반적인 경우 이는 사용자가 사이트를 떠날 때 발생합니다. (Apache는 닫힌 소켓을 인식하고 PHP 인스턴스를 종료합니다.) 서버 측에서 소켓을 닫을 수있는 주된 시간은 잠시 동안 데이터가 없음을 알고있는 경우입니다. 클라이언트에게 보내는 마지막 메시지는 특정 시간에 다시 오라고 말하는 것입니다. 예를 들어 주식 스트리밍의 경우 오후 8시에 연결을 닫고 고객에게 8 시간 후에 다시 오라고 말할 수 있습니다 (나스닥이 오전 4 시부 터 오후 8 시까 지 견적을 위해 열려 있다고 가정). 금요일 저녁 당신은 그들에게 월요일 아침에 돌아 오라고 말한다. (SSE에 대한 책이 있으며이 주제에 대한 몇 가지 섹션을 제공합니다.)

"...이 경우 PHP는 이런 종류의 서버에 적합한 기술이 아닙니다.하지만 지금까지 본 모든 데모는 PHP가 이것에 적합하다는 것을 암시합니다. 혼란스러워 ... "

글쎄요, 사람들은 PHP가 일반 웹 사이트에 적합한 기술이 아니라고 주장하며 옳습니다. 전체 LAMP 스택을 C ++로 교체하면 훨씬 적은 메모리와 CPU 주기로 수행 할 수 있습니다. 그러나 이것에도 불구하고 PHP는 대부분의 사이트에 잘 작동합니다. 친숙한 C와 유사한 구문과 많은 라이브러리의 조합으로 인해 웹 작업에 매우 생산적인 언어입니다. 사용 사례 (예 : Facebook 및 Wikipedia). 이는 기본적으로 스트리밍 기술로 PHP를 선택할 수있는 동일한 이유입니다.

일반적인 설정은 PHP 인스턴스 당 NASDAQ에 대한 하나의 연결이 아닙니다. 대신 NASDAQ에 대한 단일 연결 또는 클러스터의 각 머신에서 NASDAQ에 대한 단일 연결이있는 다른 프로세스를 갖게됩니다. 그런 다음 가격을 SQL / NoSQL 서버 또는 공유 메모리로 푸시합니다. 그런 다음 PHP는 해당 공유 메모리 (또는 데이터베이스)를 폴링하고 데이터를 푸시합니다. 또는 데이터 수집 서버가 있고 각 PHP 인스턴스가 해당 서버에 대한 소켓 연결을 엽니 다. 데이터 수집 서버는 업데이트를 수신 할 때 각 PHP 클라이언트에 업데이트를 푸시하고 해당 데이터를 클라이언트에 푸시합니다.

스트리밍에 Apache + PHP를 사용할 때 발생하는 주요 확장 성 문제는 각 Apache 프로세스의 메모리입니다. 하드웨어의 메모리 한계에 도달하면 클러스터에 다른 시스템을 추가하거나 Apache를 루프에서 제거하고 전용 HTTP 서버를 작성하기로 비즈니스 결정을 내립니다. 후자는 PHP에서 수행 할 수 있으므로 기존의 모든 지식과 코드를 재사용하거나 전체 응용 프로그램을 다른 언어로 다시 작성할 수 있습니다. 저의 순수한 개발자는 전용의 간소화 된 HTTP 서버를 C ++로 작성했습니다. 내 매니저가 다른 상자를 추가 할 것입니다.


각 Apache 연결 프로세스가 메모리를 소비하므로 대신 Nginx를 사용하는 것이 더 낫습니까?
Zhang Buzz

@ZhangBuzz 내가 Apache + PHP라고 말한 곳에서는 "웹 서버 + PHP 프로세스"를 의미하므로 기본적으로 다른 웹 서버를 사용하는 것과 차이가 없습니다.
Darren Cook


또한 Nginx는 더 적은 메모리를 사용하기 때문에 훨씬 더 효율적일 수 있습니다. blog.webfaction.com/2008/12/…
Enrique

32

서버 전송 이벤트는 서버 측에서 클라이언트 측으로의 실시간 업데이트를위한 것입니다. 첫 번째 예에서는 서버로부터의 연결이 유지되지 않고 클라이언트가 3 초마다 다시 연결을 시도하고 서버에서 보낸 이벤트를 ajax 폴링과 차이가 없도록 만듭니다.

따라서 연결이 지속되도록하려면 코드를 루프로 래핑하고 지속적으로 업데이트를 확인해야합니다.

PHP는 스레드 기반이며 연결된 사용자가 많을수록 서버의 리소스가 부족해집니다. 이 문제는 스크립트 실행 시간을 제어하여 해결할 수 있으며 시간 (예 : 10 분)을 초과하면 스크립트를 종료 할 수 있습니다. EventSource지연이 허용 가능한 범위에 있도록 API가 자동으로 다시 연결한다.

또한 내 PHP 라이브러리에서 서버 전송 이벤트를 확인하면 PHP에서 서버 전송 이벤트 를 수행하는 방법에 대해 더 많이 이해하고 코딩을 더 쉽게 할 수 있습니다.


5
"이 문제는 스크립트 실행 시간을 제어하여 해결할 수 있으며 시간이 초과되면 스크립트를 종료 할 수 있습니다."에 대해 자세히 설명해 주시겠습니까? 사용자 수가 너무 많으면 사용자가 3 초만에 다시 연결하기 때문에 연결을 닫아 리소스 사용량을 크게 향상시킬 수 있습니까?
누가 복음

4

나는 sse techink가 모든 지연 데이터를 클라이언트에 전송한다는 것을 알았습니다.

<?php
        session_start();
        header('Content-Type: text/event-stream');
        header('Cache-Control: no-cache'); // recommended to prevent caching of event data
        require 'sse.php';
        if ($_POST['message'] != ""){
                $_SESSION['message'] = $_POST['message'];
                $_SESSION['serverTime'] = time();
        }
        sendMsg($_SESSION['serverTime'], $_SESSION['message'] );
?>

sse.php는 다음과 같습니다.

<?php
function sendMsg($id, $msg) {
  echo "id: $id" . PHP_EOL;
  echo "data: $msg" . PHP_EOL;
  echo PHP_EOL;
  ob_flush();
  flush();
}
?>

sseSerer.php에서 세션을 시작하고 세션 변수를 사용합니다! 문제를 극복하기 위해.

또한 variable message"업데이트"메시지를 원할 때마다 Ajax (게시 및 값 설정)를 통해 sseServer.php를 호출합니다 .

이제 jQuery (javascript)에서 다음과 같이합니다. 1st) 전역 변수를 선언합니다. var timeStamp = 0; 2nd) 다음 알고리즘을 사용합니다.

if(typeof(EventSource)!=="undefined"){
        var source=new EventSource("sseServer.php");
        source.onmessage=function(event)
        if ((timeStamp!=event.lastEventId) && (timeStamp!=0)){
                /* this is initialization */
                timeStamp=event.lastEventId;
                $.notify("Please refresh "+event.data, "info");
        } else {
                if (timeStamp==0){
                         timeStamp=event.lastEventId;
                }
        } /* fi */

} else {
        document.getElementById("result").innerHTML="Sorry, your browser does not support server-sent events...";
} /* fi */

의 줄에 $.notify("Please refresh "+event.data, "info"); 메시지를 처리 ​​할 수 ​​있습니다.

제 경우에는 jQuery 알림을 보내곤했습니다.

sseServer.php가 "무한 루프"와 같은 작업을 수행하므로 POST를 통해 "메시지"를 전달하기 위해 POSIX PIPES 또는 DB 테이블을 대신 사용할 수 있습니다.

내 문제는 위의 코드가 모든 클라이언트에게 "메시지"를 보내는 것이 아니라 쌍 (sseServer.php를 호출 한 클라이언트가 모든 쌍에 대해 개별적으로 작동 함)에게만 전송된다는 것입니다. 따라서 technik을 변경하고 "메시지"를 트리거하려는 페이지에서 DB 업데이트를 한 다음 sseServer.php 대신 POST를 통해 메시지를 가져 오면 DB 테이블에서 가져옵니다.

도움이 되었기를 바랍니다.


3

이것은 당신의 어플리케이션에 대한 구조적인 질문입니다. 실시간 이벤트는 처음부터 생각하고 싶은 것이므로이를 중심으로 애플리케이션을 설계 할 수 있습니다. mysql(i)_query문자열 쿼리를 사용하여 임의의 메서드를 실행하고 어떤 종류의 중개자를 통해 전달하지 않는 응용 프로그램을 작성했다면 많은 경우 응용 프로그램을 다시 작성하거나 지속적인 서버 측 폴링.

그러나 엔티티를 객체로 관리하고 일종의 중간 클래스를 통해 전달하면 해당 프로세스에 연결할 수 있습니다. 이 예를보십시오 :

<?php
class MyQueryManager {
    public function find($myObject, $objectId) {
        // Issue a select query against the database to get this object
    }

    public function save($myObject) {
        // Issue a query that saves the object to the database
        // Fire a new "save" event for the type of object passed to this method
    }

    public function delete($myObject) {
        // Fire a "delete" event for the type of object
    }
}

애플리케이션에서 저장할 준비가되면 :

<?php
$someObject = $queryManager->find("MyObjectName", 1);
$someObject->setDateTimeUpdated(time());
$queryManager->save($someObject);

이것은 가장 우아한 예는 아니지만 괜찮은 빌딩 블록 역할을해야합니다. 실제 지속성 레이어에 연결하여 이러한 이벤트 트리거를 처리 할 수 ​​있습니다. 그런 다음 서버를 망치지 않고 즉시 (가능한 한 실시간으로) 얻을 수 있습니다 (데이터베이스를 지속적으로 쿼리하고 상황이 변경되었는지 확인할 필요가 없기 때문입니다).

분명히 이런 방식으로 데이터베이스에 대한 수동 변경 사항을 포착하지 못할 것입니다.하지만 데이터베이스에 어떤 빈도로든 수동으로 작업을 수행하는 경우 다음 중 하나를 수행해야합니다.

  • 수동으로 변경해야하는 문제 해결
  • 프로세스를 촉진하는 도구를 만들고 이러한 이벤트를 발생시킵니다.

3
Colin-귀하의 답변에 감사드립니다. 제 잘못입니다. 제 질문은 명확하지 않습니다.하지만 이것은 제가 요청한 것이 아닙니다. 내가 의미 물어 것은 이것이다 ... 당신이 당신의 "서버"로 PHP를 사용하는 경우 - 않습니다 당신이 실행하는 클라이언트 필요에 EventSource에서 호출 PHP 스크립트 전체 시간 클라이언트가 여기에 연결되어 있습니까? 즉, 동시 사용자가 1,000 명이라면 PHP 스크립트의 동시 인스턴스 1,000 개를 실행하는 별도의 스레드 1,000 개가 있습니까? 그게 가능합니까? 그리고 언제 PHP 스크립트 를 종료 해야하는지 어떻게 알 수 있습니까 ( "살아있는"상태로 유지하기 위해 반복된다고 가정)?
mattstuehler 2013 년

-7

기본적으로 PHP는 이런 종류의 기술에 적합하지 않습니다. 예, 작동하도록 만들 수 있지만 높은 부하에서 재앙이 될 것입니다. 우리는 웹 소켓을 통해 주식 변경 신호를 수십 명의 thousends 사용자에게 보내는 스톡 서버를 운영하고 있습니다. 그리고 PHP를 사용한다면 ... 글쎄요, 우리는 할 수 있지만 수제 사이클은 악몽 일뿐입니다. 모든 단일 연결은 서버에서 별도의 프로세스를 만들거나 일종의 데이터베이스에서 연결을 처리해야합니다.

단순히 nodejs와 socket.io를 사용하십시오. 며칠 안에 쉽게 시작하고 서버를 실행할 수 있습니다. Nodejs에도 자체 제한이 있지만 웹 소켓 (및 SSE) 연결의 경우 이제 가장 강력한 기술입니다.

그리고 또한-SSE는보기만큼 좋지 않습니다. 웹 소켓의 유일한 장점은 패킷이 기본적으로 gzip으로 압축된다는 것입니다 (ws는 gzip으로 압축되지 않음). 단점은 SSE가 단방향 연결이라는 것입니다. 사용자가 구독자에 다른 주식 기호를 추가하려면 ajax 요청을해야합니다 (원본 제어와 관련된 모든 문제 포함 및 요청 속도가 느려짐). websockets에서 클라이언트와 서버는 하나의 열린 연결에서 양방향으로 통신하므로 사용자가 거래 신호를 보내거나 견적을 구독하면 이미 열린 연결로 문자열을 보냅니다. 그리고 그것은 빠릅니다.


2
기본적으로 node.js의 이벤트 루프와 동일한 방식으로 React.php를 사용할 수 있습니다.
Matěj Koubík

3
PHP가 최선의 선택이 아니라고 말하는 것이 좋지만, 적어도 OP가 요청한 것을 포함해야한다고 생각합니다.
Nishchal Gautam
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.