8
votes

Comment mettre en œuvre une écoute des événements dans PHP

Voici mon problème: j'ai un script (appelons-le comet.php) Whick est requidé par un script client AJAX et attendre que cela se produise comme suit:

while(no_changes){
    usleep(100000);
    //check for changes
}


5 commentaires

Qu'essayez-vous d'atteindre? La méthode habituelle consiste à avoir le client d'appeler le script périodiquement pour vérifier les modifications. Y a-t-il une raison pour laquelle vous voulez le faire serveur?


PHP n'est pas vraiment une langue que vous devez utiliser pour la comète. Utilisez node.js ou quelque chose d'autre qui fonctionne de manière asynchrone (tornade python ou greenlets par exemple). En utilisant PHP en cours d'exécution sur un serveur Web de fil / processus, vous avez une énorme générale.


@ Juhana, la raison est de Éviter Vérification périodique du changement et avoir une solution Reverse-Ajax . @thieftmaster je sais qu'il y a une solution de serveur comète là-bas, mais je pense vraiment qu'un backend PHP peut être possible et aussi longtemps que j'écris mon entreprise de connexion à PHP, il serait vraiment préférable de ne pas réécrire dans une autre langue en évitant le code reproduction. Pouvez-vous s'il vous plaît expliquer pourquoi un backend de la comète PHP serait que les frais généraux?


Je peux voir que, mais y a-t-il une raison d'éviter le contrôle périodique?


Oui, il produit beaucoup de frais généraux de réseau, en fonction de la fréquence de votre nouvelle mise à jour.


5 Réponses :


4
votes

Cela dépend vraiment de ce que vous faites dans votre script de serveur. Il y a des situations dans lesquelles vous n'avez aucune option mais de faire ce que vous faites au-dessus.

Cependant, si vous faites quelque chose qui implique un appel à une fonction qui bloquera jusqu'à ce que quelque chose se passe, vous pouvez utiliser cela pour éviter la course. au lieu du USLEeP () appel (qui est imho la partie qui serait considérée comme "mauvaise pratique").

dire que vous attendiez des données d'un fichier ou d'une autre sorte de flux qui bloque. Vous pouvez faire ceci: xxx

vraiment, php est la mauvaise langue pour faire des choses comme ça. Mais il y a des situations (je sais parce que je les ai traitées moi-même) où PHP est la seule option.


6 commentaires

En fait, j'aimerais réduire les frais généraux du processeur en supprimant le noop tout en (c'est pourquoi il y a l'appel usleep ())


@Artoale Vous ne pouvez pas attendre un événement sans une sorte de boucle dans PHP - il n'y a pas de gestionnaires d'événements comme par ex. JavaScript. Mais en le faisant comme indiqué ci-dessus, vous laissez le fgets () appeler l'attente, plutôt que sur check-sommeil-check-check-check ... dans votre exemple, si l'événement se produit pendant A USLEEP () Vous devrez attendre la fin du sommeil avant de pouvoir le gérer. En utilisant la vérification (blocage) en tant que condition de boucle, fgets () renvoie immédiatement dès que l'événement est arrivé et que vous pouvez le gérer immédiatement.


Ok, tu as raison. Le point est que avec System V IPC Je peux utiliser le bloc de blocage pour Le sémaphore acquérir (ce qui aboutit à la même solution que vous avez proposé) le problème est que je ne sais pas vraiment comment utiliser SEMAPHORE pour avoir un comportement d'application «d'événement».


Je ne peux pas vous aider là-bas J'ai peur, Sempaphore est quelque chose que je n'ai jamais essayé de mettre en œuvre. Qu'est-ce que vous essayez de faire exactement? Quel est l'événement que vous attendez?


Mmm ... disons par exemple un nouveau message à envoyer sur une chaîne de discussion (bien sûr, réimplayer un moteur de discussion Ce n'est pas le meilleur choix, mais est juste par exemple))


Donc, vraisemblablement, vous auriez un processus de démon qui collecte les messages, puis lorsque l'on est disponible, le démon enverrait le processus PHP un sémaphore et le processus PHP récupère le message (à partir d'une base de données?) Et pousserait-le sur le client?



2
votes

Autant que j'aime PHP, je dois dire que PHP n'est pas le meilleur choix pour cette tâche. Nœud.js est beaucoup, beaucoup mieux pour ce genre de chose et ça échoue vraiment bien. Il est également assez simple de mettre en œuvre si vous avez des connaissances JS.

Maintenant, si vous ne voulez pas perdre de cycles CPU, vous devez créer un script PHP qui se connectera à un serveur d'une sorte sur un certain port. Le serveur spécifié doit écouter les connexions sur le port choisi et chaque fois que la quantité de temps de temps Vérifiez tout ce que vous souhaitez vérifier (DB entrées pour les nouveaux messages par exemple), puis il envoie le message à chaque client connecté que la nouvelle entrée est prête.

Maintenant, il n'est pas difficile de mettre en œuvre cette architecture d'attente d'événement en PHP, mais cela vous prendrait littéralement 5 minutes pour le faire avec node.js et Socket.io, sans vous soucier de savoir si cela fonctionnera dans la majorité des navigateurs .


0 commentaires

0
votes

Je suis d'accord avec le consensus ici que PHP n'est pas la meilleure solution ici. Vous devez vraiment regarder dédié Technologies en temps réel pour la solution à cette Problème asynchrone de la fourniture de données de votre serveur à vos clients. On dirait que vous essayez d'implémenter un interrogation http-long qui n'est pas une chose facile à résoudre le navigateur croisé. Il a été abordé de nombreuses fois par des développeurs de produits comiques, de sorte que vous vous suggérez de regarder une solution de comète, voire meilleure une solution Websocket avec support de repli pour les navigateurs plus anciens.

Je vous suggère de laisser PHP effectuer la fonctionnalité de l'application Web qu'il est bon et choisissez une solution dédiée à votre fonctionnalité asynchrone réel, éventuelle et asynchrone.


0 commentaires

14
votes

Vous pouvez résoudre ce problème à l'aide de Zeromq .

Zeromq est une bibliothèque qui fournit des prises suralimentées pour Changer de choses (threads, processus et même des machines séparées) ensemble. p>

Je suppose que vous essayez de pousser les données du serveur au client. Eh bien, un bon moyen de le faire consiste à utiliser le eventsource API ( Polyfills disponibles ). P>

client.js strong> p>

se connecte à Stream.php via eventsource. p> xxx pré>

routeur.php strong> p>

Il s'agit d'un processus de longue date qui écoute pour entraver messages et les envoie à quiconque à l'écoute. p> xxx pré>

stream.php stry> p>

Chaque utilisateur de connexion au site obtient son propre stream.php. Ce script est à long terme et attend tous les messages du routeur. Une fois que cela reçoit un nouveau message, cela émettra ce message dans Format EventsSource. P>

<?php

$context = new ZMQContext();

$sock = $context->getSocket(ZMQ::SOCKET_PUSH);
$sock->connect("tcp://127.0.0.1:5555");

$msg = json_encode(array('type' => 'debug', 'data' => array('foo', 'bar', 'baz')));
$sock->send($msg);

$msg = json_encode(array('data' => array('foo', 'bar', 'baz')));
$sock->send($msg);


2 commentaires

Remarque: j'ai récemment fait des points de repère. À un moment donné, cela n'allume pas très bien. J'ai essayé d'envoyer quelques milliers de messages en peu de temps avec quelques centaines de clients connectés. Si vous utilisez Apache, il ralentira la quantité de commutation de contexte entre les threads. Sur un noeud de points ou un module Nginx-Push-Stream sera les meilleurs outils pour le faire. Néanmoins, il est possible avec PHP et cela fonctionne.


Aimez simplement la facilité et la simplicité de cela ainsi que l'exemple très descriptif. 6 ans en bas de la ligne et toujours une réponse simple à jour. Merci!