Funzione PHP socket_set_timeout(): tutto quello che devi sapere
Scopri come usare socket_set_timeout() in PHP per impostare un timeout su operazioni di lettura/scrittura su stream e gestire connessioni lente.
Quando uno script legge da una connessione di rete, un server lento o non raggiungibile può lasciare PHP bloccato indefinitamente, occupando un worker e frustrando gli utenti. La funzione socket_set_timeout() imposta una scadenza sulle operazioni di lettura/scrittura in modo che una connessione bloccata fallisca rapidamente invece di restare in attesa. Questo articolo spiega esattamente cosa controlla, le insidie più comuni e come rilevare un timeout quando si verifica.
Cosa fa la funzione socket_set_timeout()
socket_set_timeout() imposta il timeout per le operazioni di I/O — fread(), fgets(), fwrite(), ecc. — su uno stream aperto con fsockopen() o pfsockopen(). Se una lettura o scrittura non si completa entro la scadenza, l'operazione termina anticipatamente e lo stream viene contrassegnato come scaduto.
Due cose che non fa:
- Non influisce sul timeout di connessione. Questo è il quinto argomento di
fsockopen($host, $port, $errno, $errstr, $connectTimeout).socket_set_timeout()governa solo il trasferimento dei dati dopo che la connessione è stata stabilita. - Non fa fallire la chiamata in modo evidente. Una lettura che va in timeout restituisce i dati ricevuti fino a quel momento (spesso una stringa vuota) e imposta un flag — devi verificare quel flag manualmente con
stream_get_meta_data().
Attenzione al nome: nonostante il prefisso
socket_, questa funzione appartiene alla famiglia degli stream, non all'estensione Sockets. Funziona su risorse difsockopen(), mai su una risorsa disocket_create(). Da PHP 8.0 è un alias deprecato distream_set_timeout()— preferisci quel nome nel nuovo codice.
Sintassi
socket_set_timeout(resource $stream, int $seconds, int $microseconds = 0): bool| Parametro | Descrizione |
|---|---|
$stream | Una risorsa stream aperta restituita da fsockopen() o pfsockopen(). |
$seconds | Il timeout in secondi interi. |
$microseconds | Tempo aggiuntivo in microsecondi (opzionale, predefinito 0). |
Restituisce true in caso di successo e false in caso di errore (ad esempio, se $stream non è una risorsa stream valida).
Un esempio pratico
Apri una connessione, imposta un timeout di lettura di 5 secondi, poi verifica se una lettura è andata in timeout:
<?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);L'elemento chiave è la chiamata a stream_get_meta_data(): il suo elemento timed_out è l'unico modo affidabile per distinguere un timeout reale da una connessione che si è semplicemente chiusa.
Lettura in un ciclo
Quando leggi un'intera risposta, controlla timed_out a ogni iterazione in modo che un blocco a metà trasferimento non tronchi silenziosamente i tuoi dati:
<?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";Insidie comuni
- Tipo di risorsa errato. Passare una risorsa di
socket_create()non produce risultati utili — usastream_set_timeout()con i socket disocket_create(), oppuresocket_set_option()perSO_RCVTIMEO/SO_SNDTIMEO. - Confondere il timeout di connessione con quello di lettura. Un lungo timeout di connessione con
fsockopen()non ti salverà da una risposta lenta; hai bisogno di entrambi. - Dimenticare di controllare
timed_out. Senza questo controllo, una lettura andata in timeout appare esattamente come la fine regolare dello stream, portando a dati silenziosamente troncati.
Funzioni correlate
fsockopen()— apre lo stream su cui questa funzione opera.stream_get_meta_data()tramite socket_get_status() — legge il flagtimed_out.socket_set_blocking()— passa uno stream tra la modalità bloccante e non bloccante.fgets()efwrite()— le chiamate di I/O a cui si applica il timeout.
Conclusione
socket_set_timeout() evita che letture e scritture di rete lente blocchino il tuo script PHP. Ricorda che funziona sugli stream di fsockopen() (non sull'estensione Sockets), governa l'I/O piuttosto che la connessione, e che devi ispezionare il flag timed_out di stream_get_meta_data() per sapere se un timeout si è effettivamente verificato. Nel nuovo codice, usa il nome moderno stream_set_timeout().