O que são os famosos Websockets?
É um protocolo de comunicação na rede. Assim como o protocolo Http, o websocket permite que uma aplicação se comunique com outra porém diferente do Http, a conexão é contínua. Isso elimina a necessidade de iniciar uma nova conexão com o serviço/servidor para nos comunicarmos com ele.
Uma analogia que pode ajudar a visualizar esse modelo de comunicação é a seguinte:
Imagine que você está chegando em um restaurante para almoçar. Ao chegar no restaurante, é abordado(a) por um garçom que vai anotar e encaminhar o seu pedido à cozinha. Assim que o pedido estiver pronto, o garçom irá levá-lo até você. Nesse exemplo, o garçom representa o protocolo Http, onde toda vez que você necessitar de um recurso da cozinha, será necessário que o garçom realize um novo trajeto da sua mesa até a cozinha e vice-versa.

Agora, imagine que no dia seguinte você foi a um restaurante diferente do anterior: esse não possui um funcionário que anota o seu pedido. Ao invés disso, utiliza um tablet por onde você registra um pedido e ele é recebido pela cozinha. Caso queira fazer um novo pedido, pode acessar o tablet a qualquer momento e realizá-lo, sem a necessidade do intermédio do garçom. Esse segundo exemplo se assemelha ao modelo de comunicação usando Websockets.

Quando vou usar websockets ?
É muito comum usar esse tipo de comunicação quando estamos trabalhando em aplicações que precisam de um fluxo de comunicação ou troca de informação constante, initerrupta ( ‘funcionam em tempo real’).
Aplicações como:
- Páginas de email, onde assim que uma nova mensagem for recebida, precisa atualizar a lista de emails na tela;
- Aplicações de chat, onde a mensagem enviada precisa ser recebida e visualizada;
- Aplicação de alarme de segurança, onde a comunicação com uma central de controle é constante para monitoramento de possíveis ameaças;
- Aplicação para edição de documentos compartilhados, onde mais de um usuário tem acesso ao mesmo recurso e as alterações devem ser visualizadas por eles.
Basicamente soluções que vão enviar/receber informações constantes onde o modelo Http não seria tão eficiente (Imagina se para atualizar a lista de emails na tela fosse necessário iniciar uma nova conexão com o servidor! Muitos recursos envolvidos).
Como usar esse protocolo?

Podemos criar uma aplicação que servirá de servidor destino onde uma outra aplicação pode se conectar e se comunicar através de um WebSocket. E é mais fácil do que parece!
Em um novo diretório, vamos fazer o seguinte:
Instalar o composer
curl -sS https://getcomposer.org/installer | php
E, depois com o composer inicializado (composer ini) e o arquivo composer.json criado, vamos instalar o pacote cboden/ratchet. Pra isso, basta rodar o comando:
composer require cboden/ratchet
O seu composer.json deve, então, ficar assim:
{
"require": {
"cboden/ratchet": "^0.4.4"
}
,"autoload": {
"psr-4": {
"App\\": "./"
}
}
}
Agora, vamos fazer o principal desenvolvimento: precisamos desenvolver uma classe que implementa uma interface. E só! Bom…não é só isso. Técnicamente vamos desenvolver uma nova classe, ou um objeto, que implementa uma interface específica que indica quais os métodos devem ser desenvolvidos na classe para que ela consiga produzir um canal de comunicação usando websockets.
Nesse exemplo a classe vai se chamar WebServer e vamos criá-la na raíz do projeto mesmo. Ela deve ficar assim:
<?php
namespace App;
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
class WebServer implements MessageComponentInterface{
protected $clients;
public function __construct()
{
$this->clients = new \SplObjectStorage;
}
public function onOpen(ConnectionInterface $conn) {
$this->clients->attach($conn);
echo "Nova conexão aberta: ".$conn->resourceId."\n";
}
public function onMessage(ConnectionInterface $from, $msg) {
echo "Nova mensagem recebida:{$msg} - [Id conexão: {$from->resourceId}]\n";
foreach($this->clients as $client) {
if($client != $from) {
$client->send($msg);
}
}
}
public function onClose(ConnectionInterface $conn) {
$this->clients->detach($conn);
echo "Conexão fechada: ".$conn->resourceId."\n";
}
public function onError(ConnectionInterface $conn, \Exception $e) {
echo "Erro: ".$e->getMessage()."\n";
$conn->close();
}
}
Essa classe implementa os métodos:
- onOpen -> Chamado quando um novo cliente se conectar no servidor;
- onMessage -> Chamado quando uma nova mensagem for enviada no servidor;
- onClose -> Chamado quando um cliente se desconecta do servidor;
- onError -> Chamado quando o servidor lançar algum erro ou exceção.
Além de possuir um atributo do tipo coleção SplObjectStorage: uma estrutura de dados do da linguagem php para armazenar objetos, que é inicializada no construtor da nossa classe. Esse atributo é usado para gerenciar os clientes conectados. Ele permite anexar, desanexar e iterar sobre objetos, o que é ideal para o caso de múltiplas conexões WebSocket, onde cada cliente é representado por um objeto.
No construtor, com código new \SplObjectStorage inicializamos essa estrutura vazia para garantir que a classe comece com uma coleção de clientes pronta para ser manipulada. Sempre que um novo cliente se conecta, ele é adicionado (com o método attach) e, quando se desconecta, é removido (com o método detach).
Com isso, temos uma classe que está pronta para receber ‘conexões via websocket’. Pra testarmos isso vamos instanciar a nossa classe em um novo arquivo chamado servidor.php (também na raíz do projeto).
<?php
require_once('vendor/autoload.php');
use Ratchet\Http\HttpServer;
use Ratchet\Server\IoServer;
use Ratchet\WebSocket\WsServer;
use App\WebServer; // Caso esteja no namespace App
$servidor = IoServer::factory(
new HttpServer(
new WsServer(
new WebServer()
)
), 8080);
echo "Servidor websocket iniciado na porta 8080. Aguardando novas conexões...\n";
$servidor->run();
Esse arquivo é responsável por importar as bibliotecas do Ratchet necessárias e é com a ajuda delas que podemos disponiilizar esse servidor na porta 8080 para acesso na web:
- \Http\HttpServer;
- \Server\IoServer;
- \WebSocket\WsServer;
Usamos o método factory da classe IoServer que recebe, como primeiro parâmetro, uma nova instância da classe HttpServer que, por sua vez, recebe uma nova instância da classe WsServer e ela, por ultimo, recebe uma nova instância da classe que criamos antes e, como segundo parâmetro, recebe em qual porta o servidor deve funcionar (no nosso caso, deixamos na porta 8080). O método vai retornar um objeto que possui o método run(). Fazemos então uma chamada para esse método run() para iniciarmos o servidor.
Depois disso, precisamos executar o arquivo direto na linha de comando:
php servidor.php
E pronto! Temos um servidor, rodando localmente, pronto para receber novas conexões de clientes usando o protocolo websocket! Por enquanto, só vamos ver a mensagem que configuramos lá no servidor.php sendo apresentada no terminal mas isso é porque ainda não conectamos nesse servidor que criamos.
Vamos então criar um arquivo com um código html e javascript que vai servir de cliente para que possamos conectar no servidor pelo navegador. Podemos chamar esse arquivo de index.html e criamos ele na raíz do projeto .
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WebSocket Chat</title>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
</head>
<body>
<h2>WebSocket Chat</h2>
<input type="text" id="message" placeholder="Enter your message">
<button id="send">Send</button>
<div id="chat"></div>
<script>
$(document).ready(function() {
var ws = new WebSocket('ws://localhost:8080');
// When receiving a message from the server
ws.onmessage = function(event) {
$('#chat').append('<p>' + event.data + '</p>');
};
// Sending a message to the server
$('#send').click(function() {
var msg = $('#message').val();
ws.send(msg);
$('#message').val('');
});
});
</script>
</body>
</html>
Ao abrirmos esse arquivo no navegador em uma nova aba e uma aba anônima podemos ver isso (a abertura em uma aba anônima serve para que possamos visualizar as conexões simultâneas e como o protocolo opera com elas).

Conclusão
WebSockets permitem comunicação bidirecional e em tempo real entre um ou mais clientes e o servidor. Ao contrário de requisições HTTP tradicionais, onde o cliente sempre inicia a conexão, os WebSockets permitem que o servidor também envie mensagens ao cliente sem que ele precise solicitar a todo momento e podem ser facilmente implementados na linguagem PHP com o auxílio do pacote Ratchet.
Consegue pensar em mais aplicações interessantes usando esse protocolo?

Muito bom o artigo, consegui reproduzir na minha máquina e funcionou muito bem!
Só uns detalhes que tive que ajustar: no WebServer.php, no método onOpen, no teu código ficou separado ConnectionInterface $conn e no composer.json tive que colocar “App\\”: “App/” invés de ./ (criei um diretório chamado App e coloquei o WebServer.php dentro)
Oi Gabriela! Que bom que gostou do artigo, fico feliz.
Muito bem observado! Obrigado pelo comentário, já fiz as correções.
Every weekend i used to visit this web page, foor thhe reason that i want
enjoyment, since this this site conations really pleasant
funny material too.