Fork me on GitHub

Grupo de desenvolvedores de PHP do estado de São Paulo
Próximos encontros e eventos? Visite a página do PHPSP no Meetup

[React PHP] Streams e Sockets

Por em em Artigos

Dando continuidade ao primeiro artigo publicado sobre o tema este texto irá discutir sobre estas duas ferramentas incríveis e facilitadores presentes no pacote React PHP: streamsockets.

 

Visão Geral

Como vimos anteriormente, o EventLoop de React PHP é capaz de organizar quais funções serão executadas no loop e também de trabalhar com streams.

Streams são um tipo especial de resource no php que abstraem operações com arquivos, compressão de dados, rede e afins. (Vide manual)

Os pontos principais a se saber sobre um stream são: (1) ele não depende da aplicação em que é chamado para funcionar e (2) são passíveis de leitura e/ou gravação.

Um bom exemplo de stream é o resource retornado pela função fopen().

 

Nota interessante

O pacote React\Stream, até o momento em que escrevo este texto, trabalha somente com resources do tipo stream. Isto pode ser conferido através da função get_resource_type().

A título de curiosidade, há uma tabela com todos os tipos de resource existentes em PHP.

 

A que veio React\Stream

Em php, streams não são estruturas muito simples de trabalhar quando queremos tratar de paralelismo: um stream quando criado em php, por padrão, é bloqueante. Trabalhar com eles de outra maneira pode ficar um tanto confuso. Note o exemplo utilizando stream_select().

Neste exemplo temos $process como resultado de proc_open(), cuja principal funcionalidade é executar um subprocesso independente da aplicação PHP. Como comando definimos a string ‘sleep 2; echo “nawarian”;’, que se executada em linha de comando deverá imprimir na tela o texto “nawarian” após 2 segundos de seu início, porém durante a sua execução a linha de comando ficaria inutilizada.

Através da função stream_set_blocking() dizemos que tanto o STDIN quanto STDOUT deste processo não serão bloqueantes. A partir deste momento a aplicação PHP torna sua execução independente do andamento de $process.

Para mostrar como o script php está independente temos um while (true) que, a cada iteração, imprime um ponto (“.”) na tela. Neste laço também verificamos, utilizando stream_select() se a linha de comando que iniciamos gerou alguma saída e, quando gerar, obtemos seu conteúdo e quebra o laço infinito.

centenas de pontos e um string(9) "nawarian\n" ao fim.

Resultado esperado do código acima

 

React\Stream

Felizmente o pacote React\Stream nos traz uma ótima abstração a ser utilizada em conjunto com o EventLoop.

Sua principal classe é React\Stream\Stream, que recebe em seu construtor um resource do tipo stream e uma instância de React\EventLoop\LoopInterface.

O exemplo acima seria reescrito da seguinte maneira:

Desta maneira não há motivo para se preocupar em definir os streams como não bloqueantes ou em como controlar a prontidão para leitura do STDOUT do subprocesso criado, React\Stream já lida com tudo para você.

De maneira semelhante conseguimos tratar de escrita em resources. Voltemos ao bom e velho fopen() para exemplificar:

Sendo $writer a saída padrão, todo conteúdo que recebermos de fopen() será enviado à saída padrão. É claro que existe uma forma muito mais simples para se fazer isto:

Onde React\Stream\Stream::pipe() direciona todo conteúdo recebido da instância, escrevendo-o em seu stream de argumento. Tudo o que recebemos de $reader foi escrito em $writer. E, como ao final foi emitido um evento end no stream $reader, o mesmo foi devidamente propagado ao $writer.

 

React\Socket

React\Socket é uma saída para facilitar o que vimos neste exemplo do texto anterior. Este pacote se utiliza do pacote React\Stream para abstrair as leituras e escritas do socket.

O mesmo exemplo apresentado lá seria representado desta menira:

 

Não há muito o que se explorar por aqui além da sua imaginação, visto que React\Socket\Server nada mais é que um React\Stream\Stream especializado em trabalhar com resources criados a partir da função stream_socket_server(). Portanto é um pacote especializado em trabalhar como um servidor TCP/IP.

A partir dele foram criadas diversas outras ferramentas, como o React\Http (componente servidor que segue o protocolo HTTP, portanto um servidor HTTP) e a famosa biblioteca Ratchet.

 

Conclusão

React\Stream é a implementação mais fundamental – depois de React\EventLoop – dos pacotes React. Atavés dela é possível lidar com resources de arquivos, subprocessos, rede e quaisquer outros que sejam do tipo stream. Isto possibilitou a criação de outros pacotes como React\Socket e React\ChildProcess.

Através destas abstrações somos capazes de utilizar diversas ferramentas externas à nossa aplicação de forma facilitada e controlada, aproveitando tudo o que o padrão reactor pode nos oferecer.

Tags: , , , , ,

Sobre Níckolas Silva

Desenvolvedor php há aproximadamente 4 anos, Níckolas é tecnólogo em Análise e Desenvolvimento de Sistemas, pós graduando em Engenharia de Software com foco em SOA e já esteve envolvido com desenvolvimento de sistemas de telecom e de gestão. Hoje dedica horas de seus dias ao estudo de tecnologias, práticas e técnicas sobre sistemas distribuídos, procurando integrar todas as áreas de atuação através destes estudos. Além disso está presente em todos eventos PHPSP+Pub, pois acredita que conversas, pessoas e cerveja são a chave para aprender e fortalecer conceitos.

Mais posts de .