Tout,
HTML5 Rocks propose un didacticiel pour débutant sur les événements envoyés par serveur (SSE):
http://www.html5rocks.com/en/tutorials/eventsource/basics/
Mais je ne comprends pas un concept important: qu'est-ce qui déclenche l'événement sur le serveur qui provoque l'envoi d'un message?
En d'autres termes - dans l'exemple HTML5 - le serveur envoie simplement un horodatage une fois:
<?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 je construisais un exemple concret - par exemple, un "mur" de style Facebook ou un ticker de stock, dans lequel le serveur "pousserait" un nouveau message au client chaque fois qu'une donnée changerait, comment cela fonctionne-t-il?
En d'autres termes ... Le script PHP a-t-il une boucle qui tourne continuellement, vérifiant la modification des données, puis envoyant une Si vous en avez un, comment savoir quand mettre fin à ce processus?
Ou bien le script PHP envoie-t-il simplement le message, puis se termine-il (comme cela semble être le cas dans l'exemple HTML5Rocks)?? Dans l'affirmative - comment obtenez-vous des mises à jour continues? Le navigateur interroge-t-il simplement PHP page à intervalles réguliers? Si tel est le cas - comment s’agit-il d’un "événement envoyé par le serveur"? En quoi cela diffère-t-il de l’écriture d’une fonction setInterval en JavaScript qui utilise AJAX pour appeler une page PHP à intervalles réguliers?
Désolé, c'est probablement une question incroyablement naïve. Mais aucun des exemples que j'ai pu trouver ne le dit clairement.
[MISE À JOUR]
Je pense que ma question était mal formulée, alors voici quelques éclaircissements.
Disons que j'ai une page Web qui devrait afficher le prix le plus récent du stock d'Apple.
Lorsque l'utilisateur ouvre la page pour la première fois, la page crée un EventSource avec l'URL de mon "flux".
var source = new EventSource('stream.php');
Ma question est la suivante: comment "stream.php" devrait-il fonctionner?
Comme ça? (pseudo-code):
<?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 d'autres termes - "stream.php" reste-t-il ouvert tant que le client est "connecté" à celui-ci?
Si tel est le cas, cela signifie-t-il que vous avez autant de threads exécutant stream.php
comme vous avez des utilisateurs simultanés? Si tel est le cas - est-ce faisable à distance ou est-il un moyen approprié de créer une application? Et comment savez-vous quand vous pouvez [~ # ~] terminer [~ # ~] une instance de stream.php
?
Mon impression naïve est que, si tel est le cas, PHP n'est pas une technologie adaptée à ce type de Mais toutes les démos que j'ai vues jusqu'à présent impliquent que PHP est parfait pour ça, c'est pourquoi je suis si confus ...
Les événements envoyés par le serveur doivent être mis à jour en temps réel du côté serveur au côté client. Dans le premier exemple, la connexion du serveur n'est pas conservée et le client essaie de se connecter à nouveau toutes les 3 secondes et les événements envoyés par le serveur ne font aucune différence avec l'interrogation ajax.
Donc, pour que la connexion persiste, vous devez envelopper votre code dans une boucle et vérifier les mises à jour en permanence.
PHP est basé sur les threads et plus d’utilisateurs connectés feront que le serveur sera à court de ressources. Ce problème peut être résolu en contrôlant le temps d’exécution du script et en mettant fin au script s’il dépasse un certain temps (c.-à-d. 10 minutes). L'API EventSource
se connectera automatiquement à nouveau, de sorte que le délai est acceptable.
Consultez également ma bibliothèque PHP pour les événements envoyés par le serveur , vous en apprendrez plus sur la façon de créer des événements envoyés par le serveur dans PHP et faciliter le codage.
"... Est-ce que" stream.php "reste ouvert tant que le client est" connecté "à celui-ci?"
Oui, et votre pseudo-code est une approche raisonnable.
"Et comment savez-vous quand vous pouvez terminer une instance de stream.php?"
Dans le cas le plus typique, cela se produit lorsque l'utilisateur quitte votre site. (Apache reconnaît le socket fermé et tue l'instance PHP.). La principale fois où vous pourrez fermer le socket côté serveur est si vous savez qu'il n'y aura plus de données pendant un certain temps. Le dernier message que vous envoyez au client est de lui dire de revenir à une heure donnée (par exemple, dans votre cas de stock-streaming), vous pouvez fermer la connexion à 20 heures et demander aux clients de revenir dans 8 heures (en supposant que le NASDAQ soit ouvert pour les citations de 4h à 20h) Vendredi soir, vous leur dites de revenir lundi matin (j'ai un prochain livre sur l'ESS et consacrer quelques sections à ce sujet).
"... si tel est le cas, PHP n'est pas une technologie appropriée pour ce type de serveur. Mais toutes les démos que j'ai vues jusqu'à présent impliquent que PHP est parfait pour ça, c'est pourquoi je suis si confus ... "
Les gens prétendent que PHP n'est pas une technologie appropriée pour les sites Web normaux, et ils ont raison: vous pourriez le faire avec beaucoup moins de cycles de mémoire et de CPU si vous remplaciez votre pile LAMP entière par C++. Cependant, malgré cela, PHP alimente très bien la plupart des sites. C'est un langage très productif pour le travail Web, en raison de la combinaison d'une syntaxe familière semblable à celle du C, etc. de nombreuses bibliothèques, et une solution réconfortante pour les gestionnaires, avec beaucoup de PHP programmeurs à embaucher, de nombreux livres et autres ressources, ainsi que quelques cas d'utilisation volumineux (par exemple Facebook et Wikipedia). Pour les mêmes raisons, vous pourriez choisir PHP comme technologie de diffusion en continu.
La configuration typique ne sera pas une connexion à NASDAQ par instance PHP. Au lieu de cela, vous allez avoir un autre processus avec une seule connexion au NASDAQ, ou peut-être une connexion unique de chaque machine de votre cluster au NASDAQ. Cela pousse ensuite les prix dans un serveur SQL/NoSQL ou dans la mémoire partagée. Alors PHP ne fait que sonder cette mémoire partagée (ou base de données), et expulse les données. Ou alors, disposez d'un serveur de collecte de données et chaque instance PHP s'ouvre une connexion de socket à ce serveur.Le serveur de collecte de données envoie les mises à jour à chacun de ses = PHP clients, au fur et à mesure de leur réception, puis les envoie à leur client).
Le principal problème d'évolutivité lié à l'utilisation d'Apache + PHP pour la diffusion en continu est la mémoire de chaque processus Apache. Lorsque vous atteignez la limite de mémoire du matériel, prenez la décision commerciale d'ajouter un autre ordinateur au cluster ou de couper Apache de la boucle et d'écrire un serveur HTTP dédié. Ce dernier peut être fait en PHP afin que toutes vos connaissances et votre code existants puissent être réutilisés, ou vous pouvez réécrire l’application entière dans un autre langage. Le développeur pur en moi écrirait un serveur HTTP simplifié en C++, le responsable en moi ajouterait une autre boîte.
J'ai remarqué que le techse sse envoie chaque couple de données de délai au client (par exemple, en inversant le pooling des données techniques depuis la page client e.x. Ajax regroupant des données.) Afin de résoudre ce problème, je l'ai écrit sur une page sseServer.php:
<?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'] );
?>
et le sse.php est:
<?php
function sendMsg($id, $msg) {
echo "id: $id" . PHP_EOL;
echo "data: $msg" . PHP_EOL;
echo PHP_EOL;
ob_flush();
flush();
}
?>
Notez que sur sseSerer.php, je démarre une session en utilisant une variable de session! pour surmonter le problème.
Aussi, j'appelle le sseServer.php via Ajax (affichage et valeur définie sur variable message
) Chaque fois que je veux "mettre à jour" le message.
Maintenant, au jQuery (javascript), je fais quelque chose comme ça: 1er) je déclare une variable globale var timeStamp = 0; 2nd) j'utilise l'algorithme suivant:
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 */
A la ligne: $.notify("Please refresh "+event.data, "info");
, vous pouvez gérer le message.
Dans mon cas, j’envoyais une notification jQuery.
Vous pouvez utiliser POSIX PIPES ou une table de base de données à la place pour transmettre le "message" via POST car le fichier sseServer.php fonctionne comme une "boucle infinie".
Mon problème à l'époque est que le code ci-dessus n'envoie pas le "message" à tous les clients mais uniquement à la paire (le client qui a appelé le sseServer.php fonctionne en tant qu'individu à chaque paire) donc je vais changer le technik Mise à jour de la base de données à partir de la page sur laquelle je souhaite déclencher le "message", puis le sseServer.php à la place pour obtenir le message via POST).
J'espère que j'ai de l'aide!
C'est vraiment une question structurelle à propos de votre application. Les événements en temps réel sont une chose à laquelle vous souhaitez réfléchir dès le début. Vous pouvez donc concevoir votre application en fonction de celui-ci. Si vous avez écrit une application qui exécute un ensemble de méthodes mysql(i)_query
aléatoires à l'aide de requêtes de chaînes et ne les transmet pas par un intermédiaire, vous n'aurez souvent pas le choix de réécrire. une grande partie de votre application ou faites des interrogations constantes côté serveur.
Si, toutefois, vous gérez vos entités en tant qu'objets et que vous les transmettez via une sorte de classe intermédiaire, vous pouvez vous connecter à ce processus. Regardez cet exemple:
<?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
}
}
Dans votre application, lorsque vous êtes prêt à enregistrer:
<?php
$someObject = $queryManager->find("MyObjectName", 1);
$someObject->setDateTimeUpdated(time());
$queryManager->save($someObject);
Ce n'est pas l'exemple le plus gracieux, mais il devrait servir de bloc de construction décent. Vous pouvez vous connecter à votre couche de persistance réelle pour gérer le déclenchement de ces événements. Ensuite, vous les recevez immédiatement (aussi en temps réel que possible) sans marteler votre serveur (car vous n'avez pas besoin d'interroger constamment votre base de données et de voir si les choses ont changé).
De toute évidence, vous n'accepterez pas les modifications manuelles de la base de données de cette manière - mais si vous modifiez manuellement la base de données à une fréquence quelconque, vous devez soit: