Solucionado (ver solução)
Solucionado
(ver solução)
1
resposta

Swoole WebSocket Client - Enviar Mensagem no Servidor

Olá, estou com o seguinte cenário, implementei um chat utilizando websockets, o chat server roda com Swoole (Swoole\WebSocket\Server), tive alguns problemas ao colocar em produção por conta do SSL (HTTPS, WSS), mas consegui contornar isso configurando os certificados SSL no objeto Server do Swoole, conforme o código abaixo:

$servidor = new Server($host, $port, SWOOLE_PROCESS, SWOOLE_SOCK_TCP | SWOOLE_SSL);
$servidor->set([
     'ssl_cert_file' => DIR_CERT_SSL."/fullchain.pem",
     'ssl_key_file' => DIR_CERT_SSL."/privkey.pem"
]);

As conexões realizadas via navegador (front-end) com javascript funcionam 100%, tudo dentro do esperado. No entanto, surgiu a necessidade de enviar mensagens no lado do servidor para os clientes conectados. Pesquisei nos fóruns e na documentação do Swoole e encontrei essa implementação no github , que utiliza uma instância do \Swoole\Client(SWOOLE_SOCK_TCP)

...

function __construct($host, $port, $path = '/', $origin = null)
    {
        $this->host = $host;
        $this->port = $port;
        $this->path = $path;
        $this->origin = $origin;
        $this->key = $this->generateToken(self::TOKEN_LENGHT);
    }

    public function connect()
    {
        $this->socket = new \Swoole\Client(SWOOLE_SOCK_TCP);
        if (!$this->socket->connect($this->host, $this->port)) {
            return false;
        }
        $this->socket->send($this->createHeader());
        return $this->recv();
    }

    ...

Eu instancio essa classe e chamo o método send, passando como parâmetro a mensagem que eu quero enviar, funciona 100% localmente sem o uso de SSL (WSS, HTTPS)

Exemplo:

$w = new WebSocketClient('localhost', 123456);
$w->connect();
$w->send("Olá mundo!");
$w->disconnect();

Mas quando rodo em produção, retonar a seguinte mensagem no terminal do servidor websocket:

 WARNING Socket::ssl_accept(): bad SSL client[127.0.0.1:58308], reason=252, error_string=unknown protocol

Tentei solucionar alterando o método connect() da classe WebSocketClient adicionando no parâmetro a variável global SWOOLE_SSL :

public function connect()
    {
        $this->socket = new \Swoole\Client(SWOOLE_SOCK_TCP | SWOOLE_SSL);
        if (!$this->socket->connect($this->host, $this->port)) {
            return false;
        }
        $this->socket->send($this->createHeader());
        return $this->recv();
    }

Desta forma não ocorre mais o erro, mas o algoritmo entra em loop infinito e começa a disparar a mesma mensagem várias vezes para todos os usuários conectados.

Não sei se estou utilizando a melhor abordagem para resolver essa questão, quem já passou por isso e puder auxiliar no envio de mensagens via websockets no lado do servidor agradeço.

Grato!

1 resposta
solução!

Olá pessoal, depois de muita análise nos logs, encontrei o erro, a versão do meu openSSL não era compatível com o meu OpenSwoole. Logo, estava retornando o erro de cabeçalho nas requisições https, esse erro retornava uma resposta http diferente de 200, como esse recurso estava ligado a um webhook, o Webhook ficava disparando repetidas vezes a mesma mensagem até obter o código http 200 (Success).

Atualizei o openSSL no meu ambiente e tudo passou a funcionar perfeitamente. Mantive a abordagem listada acima de instanciar uma class Swoole\Client para enviar mensagens no lado do servidor para todos as conexões do WebSocket.

Espero que isso ajude alguém no futuro, eu perdi várias horas com uma questão aparentemente simples.

Quer mergulhar em tecnologia e aprendizagem?

Receba a newsletter que o nosso CEO escreve pessoalmente, com insights do mercado de trabalho, ciência e desenvolvimento de software