Tudo,
HTML5 Rocks tem um bom tutorial para iniciantes sobre eventos enviados pelo servidor (SSE):
http://www.html5rocks.com/en/tutorials/eventsource/basics/
Mas, não entendo um conceito importante - o que dispara o evento no servidor que faz com que uma mensagem seja enviada?
Em outras palavras - no exemplo HTML5 - o servidor simplesmente envia um timestamp uma 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()));
Se eu estivesse construindo um exemplo prático - por exemplo, uma "parede" no estilo do Facebook ou uma bolsa de valores, em que o servidor "enviaria" uma nova mensagem ao cliente sempre que algum dado fosse alterado, como isso funcionaria?
Em outras palavras ... O script PHP tem um loop que é executado continuamente, verificando se há uma alteração nos dados e enviando uma mensagem sempre que encontra um? Em caso afirmativo, como saber quando terminar esse processo?
Ou - o script PHP simplesmente envia a mensagem e, em seguida, termina (como parece ser o caso no exemplo HTML5Rocks)? Se sim - como você consegue atualizações contínuas? O navegador está simplesmente pesquisando a página PHP em intervalos regulares? Se sim - como isso é um "evento enviado pelo servidor"? Como isso é diferente de escrever uma função setInterval em JavaScript que usa AJAX para chamar uma página PHP em um intervalo regular?
Desculpe - esta provavelmente é uma pergunta incrivelmente ingênua. Mas nenhum dos exemplos que consegui encontrar deixa isso claro.
[ATUALIZAR]
Acho que minha pergunta foi mal formulada, então aqui estão alguns esclarecimentos.
Digamos que eu tenha uma página da web que deve exibir o preço mais recente das ações da Apple.
Quando o usuário abre a página pela primeira vez, ela cria um EventSource com a URL do meu "fluxo".
var source = new EventSource('stream.php');
Minha pergunta é a seguinte - como deve funcionar "stream.php"?
Como isso? (pseudo-có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
}
?>
Em outras palavras - "stream.php" permanece aberto enquanto o cliente está "conectado" a ele?
Em caso afirmativo - isso significa que você tem tantos threads em execução stream.php
quanto usuários simultâneos? Em caso afirmativo - isso é remotamente viável ou uma maneira apropriada de construir um aplicativo? E como você sabe quando pode ENCERRAR uma instância de stream.php
?
Minha impressão ingênua é que, se for o caso, PHP não é uma tecnologia adequada para esse tipo de servidor. Mas todas as demos que vi até agora indicam que o PHP é adequado para isso, e é por isso que estou tão confuso ...
fonte
EventSource('stream.php')
, o cliente abre uma conexão com astream.php
qual é como chamá-lo por ajax. ESTA conexão dispara o código do servidor e mantém a conexão aberta enquanto o código do servidor tiver algo a dizer. Em seguida, a conexão fecha e após um pequeno atraso (3 segundos no cromo, eu acho) o cliente reabre a conexão que aciona seustream.php
arquivo novamente.Respostas:
Sim, e seu pseudo-código é uma abordagem razoável.
No caso mais comum, isso acontece quando o usuário sai do seu site. (O Apache reconhece o soquete fechado e elimina a instância do PHP.) O principal momento em que você pode fechar o soquete do lado do servidor é se você sabe que não haverá dados por um tempo; a última mensagem que você envia ao cliente é para dizer a ele para voltar em um determinado horário. Por exemplo, em seu caso de streaming de estoque, você poderia fechar a conexão às 20h e dizer aos clientes para voltarem em 8 horas (assumindo que o NASDAQ esteja aberto para cotações das 4h às 20h). Sexta à noite você diz a eles para voltarem na segunda de manhã. (Tenho um livro a ser publicado sobre ESS e dedico algumas seções a esse assunto.)
Bem, as pessoas argumentam que o PHP não é uma tecnologia adequada para sites normais, e estão certas: você poderia fazer isso com muito menos memória e ciclos de CPU se substituísse toda a pilha LAMP por C ++. No entanto, apesar disso, o PHP capacita a maioria dos sites muito bem. É uma linguagem muito produtiva para o trabalho na web, devido a uma combinação de uma sintaxe semelhante ao C familiar e tantas bibliotecas, e uma linguagem reconfortante para os gerentes, pois muitos programadores de PHP podem ser contratados, muitos livros e outros recursos, e alguns grandes casos de uso (por exemplo, Facebook e Wikipedia). Esses são basicamente os mesmos motivos pelos quais você pode escolher o PHP como sua tecnologia de streaming.
A configuração típica não será uma conexão ao NASDAQ por instância do PHP. Em vez disso, você terá outro processo com uma única conexão ao NASDAQ, ou talvez uma única conexão de cada máquina em seu cluster ao NASDAQ. Isso então empurra os preços para um servidor SQL / NoSQL ou para a memória compartilhada. Então o PHP apenas pesquisa essa memória compartilhada (ou banco de dados) e empurra os dados para fora. Ou tenha um servidor de coleta de dados e cada instância do PHP abre uma conexão de soquete para esse servidor. O servidor de coleta de dados envia atualizações para cada um de seus clientes PHP, conforme as recebe, e eles, por sua vez, enviam esses dados para seu cliente.
O principal problema de escalabilidade com o uso de Apache + PHP para streaming é a memória para cada processo Apache. Quando você atingir o limite de memória do hardware, tome a decisão de negócios de adicionar outra máquina ao cluster ou cortar o Apache do loop e escrever um servidor HTTP dedicado. O último pode ser feito em PHP para que todo o seu conhecimento e código existentes possam ser reutilizados, ou você pode reescrever todo o aplicativo em outra linguagem. O desenvolvedor puro em mim escreveria um servidor HTTP dedicado e simplificado em C ++. O gerente em mim acrescentaria outra caixa.
fonte
Os eventos enviados pelo servidor são para atualização em tempo real do lado do servidor para o lado do cliente. No primeiro exemplo, a conexão do servidor não é mantida e o cliente tenta se conectar novamente a cada 3 segundos e faz com que os eventos enviados pelo servidor não diferenciem o polling do Ajax.
Portanto, para fazer a conexão persistir, você precisa envolver seu código em um loop e verificar se há atualizações constantemente.
O PHP é baseado em thread e mais usuários conectados farão com que o servidor fique sem recursos. Isso pode ser resolvido controlando o tempo de execução do script e encerrando o script quando ele exceder um período de tempo (ou seja, 10 minutos). A
EventSource
API se conectará automaticamente novamente para que o atraso esteja em um intervalo aceitável.Além disso, verifique minha biblioteca PHP para eventos enviados pelo servidor , você pode entender mais sobre como fazer eventos enviados pelo servidor em PHP e torná-lo mais fácil de codificar.
fonte
Percebi que o sse techink envia todos os dados de atraso para o cliente (algo como reverter o pool de dados techink da página do cliente ex Ajax pooling data.) Portanto, para superar esse problema, fiz isso em uma página sseServer.php:
e o sse.php é:
Observe que no sseSerer.php eu inicio uma sessão e usando uma variável de sessão! para superar o problema.
Também chamo o sseServer.php via Ajax (postar e definir o valor para
variable message
) toda vez que quero "atualizar" a mensagem.Agora no jQuery (javascript) eu faço algo assim: 1º) Eu declaro uma variável global var timeStamp = 0; 2ª) eu uso o próximo algoritmo:
Na linha de:
$.notify("Please refresh "+event.data, "info");
é aí que você pode lidar com a mensagem.No meu caso, costumava enviar uma notificação jQuery.
Você pode usar POSIX PIPES ou uma tabela de banco de dados ao invés para passar a "mensagem" via POST, já que o sseServer.php faz algo como um "loop infinito".
Meu problema no momento é que o código acima NÃO ENVIA A "mensagem" para todos os clientes, mas apenas para o par (o cliente que chamou o sseServer.php funciona como individual para cada par), então vou mudar a técnica e para um Atualização do banco de dados da página que eu quero acionar a "mensagem" e, em seguida, o sseServer.php em vez de obter a mensagem via POST, ele irá obtê-lo da tabela do banco de dados.
Espero ter ajuda!
fonte
Esta é realmente uma questão estrutural sobre seu aplicativo. Eventos em tempo real são algo em que você deseja pensar desde o início, para que possa projetar seu aplicativo em torno disso. Se você escreveu um aplicativo que apenas executa um monte de
mysql(i)_query
métodos aleatórios usando consultas de string e não os passa por nenhum tipo de intermediário, então muitas vezes você não terá escolha a não ser reescrever grande parte de seu aplicativo ou sondagem constante do lado do servidor.Se, no entanto, você gerencia suas entidades como objetos e as passa por algum tipo de classe intermediária, pode se conectar a esse processo. Veja este exemplo:
Em seu aplicativo, quando você estiver pronto para salvar:
Este não é o exemplo mais elegante, mas deve servir como um bloco de construção decente. Você pode conectar-se à sua camada de persistência real para lidar com o acionamento desses eventos. Então, você os obtém imediatamente (o mais em tempo real possível) sem sobrecarregar seu servidor (já que você não precisa consultar constantemente seu banco de dados para ver se as coisas mudaram).
Obviamente, você não detectará alterações manuais no banco de dados dessa maneira - mas se estiver fazendo algo manualmente em seu banco de dados com qualquer frequência, você deve:
fonte
Basicamente, o PHP não é uma tecnologia adequada para esse tipo de coisas. Sim, você pode fazer funcionar, mas será um desastre em alta carga. Nós rodamos stockservers que enviam sinais de mudança de ações via websockets para dezenas de milhares de usuários - e se usássemos php para isso ... Bem, poderíamos, mas aqueles ciclos caseiros - é apenas um pesadelo. Cada conexão fará um processo separado no servidor ou você terá que lidar com conexões de algum tipo de banco de dados.
Basta usar nodejs e socket.io. Ele permitirá que você inicie facilmente e tenha um servidor em execução em alguns dias. O Nodejs também tem limitações próprias, mas para conexões de websockets (e SSE) agora é a tecnologia mais poderosa.
E também - SSE não é tão bom quanto parece. A única vantagem dos websockets - é que os pacotes estão sendo compactados com gzip nativamente (ws não é gzipado), mas a desvantagem é que o SSE é uma conexão de um lado. Seu usuário, se quiser adicionar outro símbolo de ação ao subscrito, terá que fazer uma solicitação ajax (incluindo todos os problemas com o controle de origem e a solicitação será lenta). Em websockets, o cliente e o servidor se comunicam de ambas as maneiras em uma única conexão aberta, portanto, se o usuário enviar um sinal de negociação ou assinar uma cotação, ele apenas enviará uma string na conexão já aberta. E é rápido.
fonte