Todas,
HTML5 Rocks tiene un buen tutorial para principiantes sobre eventos enviados por el servidor (SSE):
http://www.html5rocks.com/en/tutorials/eventsource/basics/
Pero no entiendo un concepto importante: ¿qué desencadena el evento en el servidor que hace que se envíe un mensaje?
En otras palabras, en el ejemplo de HTML5, el servidor simplemente envía una marca de tiempo una vez :
<?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()));
Si estuviera construyendo un ejemplo práctico, por ejemplo, un "muro" al estilo de Facebook o un indicador de cotización, en el que el servidor "enviaría" un nuevo mensaje al cliente cada vez que cambia algún dato, ¿cómo funciona?
En otras palabras ... ¿El script PHP tiene un bucle que se ejecuta continuamente, verificando un cambio en los datos y luego envía un mensaje cada vez que encuentra uno? Si es así, ¿cómo sabe cuándo finalizar ese proceso?
O bien, ¿el script PHP simplemente envía el mensaje y luego finaliza (como parece ser el caso en el ejemplo de HTML5Rocks)? Si es así, ¿cómo obtiene actualizaciones continuas? ¿El navegador simplemente consulta la página PHP a intervalos regulares? Si es así, ¿cómo es eso un "evento enviado por el servidor"? ¿En qué se diferencia esto de escribir una función setInterval en JavaScript que usa AJAX para llamar a una página PHP a intervalos regulares?
Lo siento, esta es probablemente una pregunta increíblemente ingenua. Pero ninguno de los ejemplos que he podido encontrar aclara esto.
[ACTUALIZAR]
Creo que mi pregunta estaba mal redactada, así que aquí tienes algunas aclaraciones.
Digamos que tengo una página web que debería mostrar el precio más reciente de las acciones de Apple.
Cuando el usuario abre la página por primera vez, la página crea un EventSource con la URL de mi "flujo".
var source = new EventSource('stream.php');
Mi pregunta es la siguiente: ¿cómo debería funcionar "stream.php"?
¿Me gusta esto? (pseudocódigo):
<?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
}
?>
En otras palabras, ¿"stream.php" permanece abierto mientras el cliente esté "conectado" a él?
Si es así, ¿eso significa que tiene tantos subprocesos en ejecución stream.php
como usuarios simultáneos? Si es así, ¿es eso remotamente factible o una forma adecuada de crear una aplicación? ¿Y cómo sabe cuándo puede FINALIZAR una instancia de stream.php
?
Mi impresión ingenua es que, si este es el caso, PHP no es una tecnología adecuada para este tipo de servidor. Pero todas las demostraciones que he visto hasta ahora implican que PHP está bien para esto, por eso estoy tan confundido ...
fuente
EventSource('stream.php')
, el cliente abre una conexión con lastream.php
que es como llamarlo por ajax. ESTA conexión activa el código del lado del servidor y mantiene la conexión abierta siempre que el código del lado del servidor tenga algo que decir. Luego, la conexión se cierra y, después de un breve retraso (3 segundos en Chrome, creo), el cliente vuelve a abrir la conexión que activa sustream.php
archivo nuevamente.Respuestas:
Sí, y su pseudocódigo es un enfoque razonable.
En el caso más típico, esto sucede cuando el usuario abandona su sitio. (Apache reconoce el socket cerrado y mata la instancia de PHP). El momento principal en que puede cerrar el socket desde el lado del servidor es si sabe que no habrá datos durante un tiempo; el último mensaje que envía al cliente es para decirle que vuelva en un momento determinado. Por ejemplo, en su caso de transmisión de acciones, podría cerrar la conexión a las 8 p.m. y decirle a los clientes que regresen en 8 horas (suponiendo que NASDAQ esté abierto para cotizaciones de 4 a.m. a 8 p.m.). El viernes por la noche les dices que regresen el lunes por la mañana. (Tengo un próximo libro sobre SSE y dedico un par de secciones a este tema).
Bueno, la gente argumenta que PHP no es una tecnología adecuada para sitios web normales, y tienen razón: podría hacerlo con mucha menos memoria y ciclos de CPU si reemplazara toda su pila LAMP con C ++. Sin embargo, a pesar de esto, PHP funciona perfectamente en la mayoría de los sitios. Es un lenguaje muy productivo para el trabajo web, debido a una combinación de una sintaxis familiar similar a C y tantas bibliotecas, y una reconfortante para los gerentes ya que hay muchos programadores PHP para contratar, muchos libros y otros recursos, y algunos grandes casos de uso (por ejemplo, Facebook y Wikipedia). Esas son básicamente las mismas razones por las que puede elegir PHP como tecnología de transmisión.
La configuración típica no será una conexión a NASDAQ por instancia de PHP. En su lugar, tendrá otro proceso con una sola conexión al NASDAQ, o quizás una sola conexión de cada máquina en su clúster al NASDAQ. Eso luego empuja los precios a un servidor SQL / NoSQL o a la memoria compartida. Luego PHP simplemente sondea esa memoria compartida (o base de datos) y envía los datos. O tenga un servidor de recopilación de datos y cada instancia de PHP abre una conexión de socket a ese servidor. El servidor de recopilación de datos envía actualizaciones a cada uno de sus clientes PHP, a medida que las recibe, y ellos, a su vez, envían esos datos a su cliente.
El principal problema de escalabilidad con el uso de Apache + PHP para la transmisión es la memoria para cada proceso de Apache. Cuando alcance el límite de memoria del hardware, tome la decisión comercial de agregar otra máquina al clúster o elimine Apache del ciclo y escriba un servidor HTTP dedicado. Esto último se puede hacer en PHP para que todo su conocimiento y código existentes se puedan reutilizar, o puede reescribir toda la aplicación en otro idioma. El desarrollador puro que hay en mí escribiría un servidor HTTP dedicado y optimizado en C ++. El gerente en mí agregaría otra caja.
fuente
Los eventos enviados por el servidor se actualizan en tiempo real del lado del servidor al lado del cliente. En el primer ejemplo, la conexión desde el servidor no se mantiene y el cliente intenta conectarse nuevamente cada 3 segundos y hace que los eventos enviados por el servidor no sean diferentes al sondeo ajax.
Por lo tanto, para que la conexión persista, debe envolver su código en un bucle y buscar actualizaciones constantemente.
PHP está basado en subprocesos y los usuarios más conectados harán que el servidor se quede sin recursos. Esto se puede resolver controlando el tiempo de ejecución del script y finalizando el script cuando exceda una cantidad de tiempo (es decir, 10 minutos). La
EventSource
API se conectará automáticamente de nuevo para que el retraso esté en un rango aceptable.Además, consulte mi biblioteca PHP para eventos enviados por el servidor , puede comprender más sobre cómo hacer eventos enviados por el servidor en PHP y facilitar la codificación.
fuente
Me he dado cuenta de que el sse techink envía cada par de datos de demora al cliente (algo así como invertir el techink de datos de agrupación de la página del cliente, por ejemplo, los datos de agrupación de Ajax), así que para superar este problema hice esto en una página sseServer.php:
y el sse.php es:
¡Observe que en sseSerer.php comienzo una sesión y uso una variable de sesión! para superar el problema.
También llamo al sseServer.php a través de Ajax (publicando y estableciendo valor en
variable message
) cada vez que quiero "actualizar" el mensaje.Ahora en jQuery (javascript) hago algo así: 1º) declaro una variable global var timeStamp = 0; 2do) uso el siguiente algoritmo:
En la línea de: ¿
$.notify("Please refresh "+event.data, "info");
está ahí donde puede manejar el mensaje?Para mi caso, solía enviar una notificación de jQuery.
Puede usar POSIX PIPES o una tabla DB en su lugar para pasar el "mensaje" a través de POST ya que sseServer.php hace algo así como un "bucle infinito".
Mi problema en ese momento es que el código anterior NO ENVÍA EL "mensaje" a todos los clientes, sino solo al par (el cliente que llamó al sseServer.php funciona como individuo para cada par) así que cambiaré el technik y un Actualización de la base de datos desde la página en la que quiero activar el "mensaje" y luego el sseServer.php en su lugar para obtener el mensaje a través de POST lo obtendrá de la tabla DB.
¡Espero tener ayuda!
fuente
Esta es realmente una pregunta estructural sobre su aplicación. Los eventos en tiempo real son algo en lo que desea pensar desde el principio, para que pueda diseñar su aplicación en torno a ellos. Si ha escrito una aplicación que solo ejecuta un montón de
mysql(i)_query
métodos aleatorios utilizando consultas de cadena y no los pasa a través de ningún tipo de intermediario, muchas veces no tendrá más remedio que reescribir gran parte de su aplicación o hacerlo sondeo constante del lado del servidor.Sin embargo, si administra sus entidades como objetos y las pasa a través de algún tipo de clase intermedia, puede conectarse a ese proceso. Mira este ejemplo:
En su aplicación, cuando esté listo para guardar:
Este no es el ejemplo más elegante, pero debería servir como un bloque de construcción decente. Puede conectarse a su capa de persistencia real para manejar la activación de estos eventos. Luego, los obtienes de inmediato (lo más en tiempo real posible) sin martillar tu servidor (ya que no tienes necesidad de consultar constantemente tu base de datos y ver si las cosas cambiaron).
Obviamente, no detectará los cambios manuales en la base de datos de esta manera, pero si está haciendo algo manualmente en su base de datos con cualquier frecuencia, debe:
fuente
Básicamente, PHP no es una tecnología adecuada para este tipo de cosas. Sí, puede hacer que funcione, pero será un desastre con una gran carga. Ejecutamos servidores de stock que envían señales de cambio de existencias a través de websockets a decenas de miles de usuarios, y si usáramos php para eso ... Bueno, podríamos, pero esos ciclos caseros, es solo una pesadilla. Cada conexión hará un proceso separado en el servidor o tendrá que manejar las conexiones desde algún tipo de base de datos.
Simplemente use nodejs y socket.io. Le permitirá iniciar fácilmente y tener un servidor en funcionamiento en un par de días. Nodejs también tiene sus propias limitaciones, pero para las conexiones websockets (y SSE) ahora es la tecnología más poderosa.
Y también, SSE no es tan bueno como parece. La única ventaja de los websockets es que los paquetes se comprimen con gzip de forma nativa (ws no es gzip), pero la desventaja es que SSE es una conexión de un solo lado. Su usuario, si quiere agregar otro símbolo de acciones al subscripton, tendrá que realizar una solicitud ajax (incluidos todos los problemas con el control de origen y la solicitud será lenta). En websockets, el cliente y el servidor se comunican en ambos sentidos en una sola conexión abierta, por lo que si el usuario envía una señal comercial o se suscribe a cotizar, simplemente envía una cadena en la conexión ya abierta. Y es rapido.
fuente