Função PHP socket_set_blocking(): Tudo o que Você Precisa Saber
Aprenda a usar socket_set_blocking() no PHP, suas alternativas modernas e como controlar modos bloqueante e não bloqueante em sockets e streams.
Ao escrever código de rede em PHP, muitas vezes é necessário controlar se uma chamada de I/O aguarda pelos dados (modo bloqueante) ou retorna imediatamente (modo não bloqueante). A função socket_set_blocking() era o alias histórico para definir esse modo. Ela foi descontinuada no PHP 8.1 e não deve ser usada em código novo.
O problema é que a substituição correta depende do tipo de conexão que você possui, e é aqui que muitos guias erram:
- Se você usou a extensão Sockets (
socket_create(), que retorna um objetoSocket), usesocket_set_nonblock()esocket_set_block(). - Se você usou um stream (
fsockopen()oustream_socket_client(), que retornam um recurso de stream), usestream_set_blocking().
socket_set_blocking() era na verdade um alias de stream_set_blocking(), portanto só funcionava com recursos de stream — nunca com objetos Socket. Essa distinção é a chave para evitar um TypeError em tempo de execução.
Modo Bloqueante vs. Não Bloqueante
No modo bloqueante (o padrão), uma chamada de leitura ou escrita pausa a execução do script até que a operação possa ser concluída. Um socket_read() em um socket vazio simplesmente aguarda até que os bytes cheguem.
No modo não bloqueante, a mesma chamada retorna imediatamente. Se nenhum dado estiver disponível, ela retorna um resultado vazio (ou false) em vez de aguardar. Isso permite que um único script gerencie muitas conexões ou permaneça responsivo — ao custo de você ter que verificar periodicamente se os dados realmente chegaram.
| Use o modo bloqueante quando… | Use o modo não bloqueante quando… |
|---|---|
| Você lida com uma conexão por vez | Você atende muitos clientes em um único loop |
| A simplicidade importa mais que o desempenho | O script precisa permanecer responsivo |
| Uma requisição/resposta curta e previsível | Você implementa seu próprio loop de polling/eventos |
Definindo o Modo em um Objeto Socket
Se você criou a conexão com a extensão Sockets, use socket_set_nonblock() e socket_set_block():
socket_set_nonblock(Socket $socket): bool
socket_set_block(Socket $socket): boolAmbas retornam true em caso de sucesso e false em caso de falha. Um exemplo completo e executável com tratamento de erros e limpeza:
<?php
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
if ($socket === false) {
die("Socket creation failed: " . socket_strerror(socket_last_error()) . "\n");
}
// Switch to non-blocking mode
if (!socket_set_nonblock($socket)) {
die("Failed to set non-blocking mode\n");
}
echo "Socket is now non-blocking.\n";
// ... perform non-blocking socket operations ...
// Switch back to blocking mode if needed
socket_set_block($socket);
echo "Socket is now blocking again.\n";
socket_close($socket);Não chame
stream_set_blocking($socket, false)em um objetoSocket—socket_create()retorna uma instância deSocket, estream_set_blocking()só aceita um recurso de stream. Passar umSocketlança umTypeError.
Definindo o Modo em um Stream
Se você abriu a conexão com fsockopen() ou stream_socket_client(), você tem um recurso de stream e deve usar stream_set_blocking():
stream_set_blocking(resource $stream, bool $enable): bool$stream: o recurso de stream a ser configurado.$enable:truepara modo bloqueante,falsepara modo não bloqueante.
<?php
$stream = stream_socket_client('tcp://example.com:80', $errno, $errstr, 5);
if ($stream === false) {
die("Connect failed: $errstr ($errno)\n");
}
// Switch the stream to non-blocking mode
if (!stream_set_blocking($stream, false)) {
die("Failed to set non-blocking mode\n");
}
echo "Stream is now non-blocking.\n";
fclose($stream);Um Loop de Leitura Não Bloqueante
O modo não bloqueante só é útil se você realizar polling. Um padrão típico envia uma requisição e verifica repetidamente se há uma resposta sem travar o script:
<?php
$stream = stream_socket_client('tcp://example.com:80', $errno, $errstr, 5);
if ($stream === false) {
die("Connect failed: $errstr ($errno)\n");
}
stream_set_blocking($stream, false);
fwrite($stream, "GET / HTTP/1.0\r\nHost: example.com\r\n\r\n");
$response = '';
$start = time();
while (!feof($stream) && time() - $start < 5) {
$chunk = fread($stream, 8192);
if ($chunk === '' || $chunk === false) {
// No data yet — do other work or wait briefly
usleep(50000); // 50 ms
continue;
}
$response .= $chunk;
}
echo substr($response, 0, 15), "\n"; // e.g. "HTTP/1.1 200 OK"
fclose($stream);A chamada usleep() evita que um loop ocupado sobrecarregue a CPU. Em produção, você normalmente substituiria esse polling manual por stream_select() para aguardar eficientemente em múltiplos streams ao mesmo tempo.
Notas de Versão
- PHP 8.1:
socket_set_blocking()foi descontinuada. Chamá-la emite um aviso de descontinuação. - A função era um alias de
stream_set_blocking(), portanto nunca aceitou objetosSocket. - Para objetos
Socket,socket_set_nonblock()/socket_set_block()sempre foram as chamadas corretas e continuam sendo suportadas.
Funções Relacionadas
socket_get_status()— inspeciona o estado de um socket, incluindo se ele está bloqueado.socket_set_timeout()— controla por quanto tempo uma operação bloqueante aguarda antes de desistir.- PHP Streams — a API de streams mais ampla à qual
stream_set_blocking()pertence.
Conclusão
Controlar o modo de bloqueio de uma conexão é essencial para construir aplicações de rede PHP responsivas. A chave é combinar a função com o tipo de conexão: use socket_set_nonblock() / socket_set_block() para objetos Socket, e stream_set_blocking() para recursos de stream. Evite a função descontinuada socket_set_blocking() em código novo e lembre-se de que o modo não bloqueante só vale a pena quando combinado com um loop de polling.