Función PHP socket_set_timeout(): Todo lo que necesitas saber
Aprende a usar socket_set_timeout() en PHP para establecer un límite de tiempo en operaciones de lectura/escritura y evitar bloqueos indefinidos.
Cuando tu script lee de una conexión de red, un servidor lento o caído puede dejar a PHP bloqueado indefinidamente, ocupando un proceso y frustrando a los usuarios. La función socket_set_timeout() establece un límite de tiempo en las operaciones de lectura/escritura para que una conexión bloqueada falle rápidamente en lugar de quedarse colgada. Este artículo explica exactamente qué controla, los errores comunes y cómo detectar un tiempo de espera cuando ocurre.
Qué hace la función socket_set_timeout()
socket_set_timeout() establece el tiempo de espera para operaciones de E/S — fread(), fgets(), fwrite(), etc. — en un stream abierto con fsockopen() o pfsockopen(). Si una lectura o escritura no se completa dentro del plazo establecido, la operación termina anticipadamente y el stream queda marcado como agotado por tiempo de espera.
Dos cosas que no hace:
- No afecta al tiempo de espera de la conexión. Ese es el quinto argumento de
fsockopen($host, $port, $errno, $errstr, $connectTimeout).socket_set_timeout()solo regula la transferencia de datos una vez que la conexión está abierta. - No hace que la llamada falle de forma explícita. Una lectura que agota el tiempo de espera devuelve los datos recibidos hasta ese momento (a menudo una cadena vacía) y establece un indicador — tienes que inspeccionar ese indicador tú mismo con
stream_get_meta_data().
Trampa de nomenclatura: A pesar del prefijo
socket_, esta función pertenece a la familia de streams, no a la extensión Sockets. Funciona con recursos defsockopen(), nunca con un recurso desocket_create(). Desde PHP 8.0 es un alias obsoleto destream_set_timeout()— prefiere ese nombre en el código nuevo.
Sintaxis
socket_set_timeout(resource $stream, int $seconds, int $microseconds = 0): bool| Parámetro | Descripción |
|---|---|
$stream | Un recurso de stream abierto devuelto por fsockopen() o pfsockopen(). |
$seconds | El tiempo de espera en segundos enteros. |
$microseconds | Tiempo adicional en microsegundos (opcional, por defecto 0). |
Devuelve true en caso de éxito y false en caso de fallo (por ejemplo, si $stream no es un recurso de stream válido).
Un ejemplo funcional
Abre una conexión, establece un tiempo de espera de lectura de 5 segundos y luego comprueba si una lectura agotó el tiempo:
<?php
// Open a TCP connection to a web server.
$stream = fsockopen("www.example.com", 80, $errno, $errstr, 10);
if (!$stream) {
echo "Connection failed: $errstr ($errno)\n";
exit;
}
// Fail any single read/write that stalls for more than 5 seconds.
socket_set_timeout($stream, 5);
// Send a minimal HTTP request.
fwrite($stream, "GET / HTTP/1.0\r\nHost: www.example.com\r\n\r\n");
// Read the first line of the response.
$line = fgets($stream, 1024);
// Check whether that read hit the timeout.
$info = stream_get_meta_data($stream);
if ($info['timed_out']) {
echo "Read timed out — the server was too slow.\n";
} else {
echo "First response line: " . trim($line) . "\n";
}
fclose($stream);La clave es la llamada a stream_get_meta_data(): su elemento timed_out es la única forma fiable de distinguir un tiempo de espera real de una conexión que simplemente se cerró.
Lectura en un bucle
Cuando lees una respuesta completa, comprueba timed_out en cada iteración para que un bloqueo a mitad de la transferencia no trunca silenciosamente tus datos:
<?php
$stream = fsockopen("www.example.com", 80, $errno, $errstr, 10);
socket_set_timeout($stream, 5);
fwrite($stream, "GET / HTTP/1.0\r\nHost: www.example.com\r\n\r\n");
$body = "";
while (!feof($stream)) {
$chunk = fgets($stream, 4096);
$info = stream_get_meta_data($stream);
if ($info['timed_out']) {
echo "Stalled before the response finished.\n";
break;
}
$body .= $chunk;
}
fclose($stream);
echo "Received " . strlen($body) . " bytes.\n";Errores comunes
- Tipo de recurso incorrecto. Pasar un recurso de
socket_create()no sirve de nada — usastream_set_timeout()con sockets desocket_create(), osocket_set_option()paraSO_RCVTIMEO/SO_SNDTIMEO. - Confundir los tiempos de espera de conexión y de lectura. Un tiempo de espera de conexión largo en
fsockopen()no te protegerá de una respuesta lenta; necesitas ambos. - Olvidar comprobar
timed_out. Sin hacerlo, una lectura que agotó el tiempo de espera tiene exactamente el mismo aspecto que un fin de stream limpio, lo que lleva a datos truncados silenciosamente.
Funciones relacionadas
fsockopen()— abre el stream sobre el que opera esta función.stream_get_meta_data()vía socket_get_status() — lee el indicadortimed_out.socket_set_blocking()— cambia un stream entre modo bloqueante y no bloqueante.fgets()yfwrite()— las llamadas de E/S a las que se aplica el tiempo de espera.
Conclusión
socket_set_timeout() evita que las lecturas y escrituras de red lentas bloqueen tu script PHP. Recuerda que funciona con streams de fsockopen() (no con la extensión Sockets), regula la E/S en lugar de la conexión, y que debes inspeccionar el indicador timed_out de stream_get_meta_data() para saber si realmente ocurrió un tiempo de espera. En el código nuevo, usa su nombre moderno, stream_set_timeout().