php stream_get_contents si blocca alla fine del stream

Soluzione alla fine della domanda

Sto scrivendo un'applicazione PHP che invia un messaggio a un server e poi legge una risposta utilizzando stream_get_contents . Io comunico con lo stesso server in un'app Android allo stesso modo. L'app Android funziona bene e risponde rapidamente, tuttavia il PHP si blocca durante la lettura della risposta dal server.

Nell'esempio di codice riportto di seguito, ho impostato una piccola dimensione del buffer di 5 byte per testare una teoria. Se rimuovo questa dimensione del buffer, si blocca, tuttavia con la dimensione di 5 byte si blocca solo sull'ultimo passaggio del ciclo:

 stream_set_timeout($this->socket, 10); //10 seconds read timeout while (!feof($this->socket)) { $breakOut = false; echo 'Reading response'.time().'<br/>'; $data = stream_get_contents($this->socket, 5); echo 'Read response'.time().'<br/>'; if ($data === false) { $this->latestErrStr = "Timed out waiting for a response."; return false; } else { $index = strpos($data, chr(3)); if ($index !== FALSE){ $breakOut = true; $data = substr($data, 0, $index); } $response .= $data; } $stream_meta_data = stream_get_meta_data($this->socket); //If we have no EOF marker then break if there are no bytes left to read if($breakOut || $stream_meta_data['unread_bytes'] <= 0) { break; } } 

L'output è il seguente:

 Reading response1387463602 Read response1387463603 Reading response1387463603 Read response1387463603 Reading response1387463603 Read response1387463603 Reading response1387463603 Read response1387463603 Reading response1387463603 Read response1387463603 Reading response1387463603 Read response1387463603 Reading response1387463603 Read response1387463603 Reading response1387463603 Read response1387463603 Reading response1387463603 Read response1387463603 Reading response1387463603 Read response1387463603 Reading response1387463603 Read response1387463603 Reading response1387463603 Read response1387463603 Reading response1387463603 Read response1387463623 

Come puoi vedere c'è un ritardo di 10 secondi tra le ultime due righe, ma nessun ritardo evidente tra gli altri.

Anche per vostra informazione, utilizzo un marcatore ETX (3) per indicare la fine di un messaggio, quindi mi fermo anche se premo questo anziché solo la fine del stream.

Sto facendo qualcosa di sbagliato? C'è un modo migliore per farlo?

Grazie in anticipo…

Modifica: solo per essere chiari, il codice di cui sopra si aspetta solo una risposta al messaggio. Non si cura di alcun dato che ritorna dopo aver ricevuto un byte ETX.

Edit2: Hangs sono stati visti fino a 40 secondi ora. Non sembra essere fissato a 10 secondi, ma stranamente sembra essere un bel numero rotondo each volta.

Soluzione (grazie a chathux) :

stream_get_contents($stream, $bytes) bloccherà fino a quando non riceverà $bytes byte o il timeout scade. Questo significa che il mio codice stava raggiungendo la fine e stava cercando di leggere 5 byte (che non esistevano), quindi era in attesa di 10 secondi prima di arrendersi.

Siccome so che la dimensione minima di un messaggio che mi viene restituita è di 49 byte, prima leggo quei 49 byte (bloccando finché non ottengo loro o 10 secondi) per compilare il field unread_bytes . Una volta ottenuto questo min(16*1024, unread_bytes) dynamicmente la dimensione del buffer a min(16*1024, unread_bytes) quindi leggo 16k alla volta o tutti i byte rimanenti, a seconda di quale sia il più piccolo. Nel mio caso questo di solito significa solo due passaggi attraverso il ciclo poiché i messaggi sono spesso piccoli (49 byte + carico utile).

Il sistema ora si blocca per circa 3 secondi invece di 10, ma si blocca in attesa dell'arrivo dei pochi byte iniziali (anziché alla fine) che possono essere sottoposti a latenza di networking e ad altri fattori normali.

la documentazione dice "stream_get_contents () opera su una risorsa di stream già aperta e restituisce il contenuto rimanente in una string, fino a un massimo di byte e partendo dall'offset specificato."

quindi, quando fornisci 5 come lunghezza massima, legge solo fino a cinque byte e continua. se non può leggere fino a 5 byte, attenderà e scadrà tra 10 secondi che hai menzionato in stream_set_timeout

esempio :

 //server side statement<br/> $data = stream_get_contents($this->socket, 5); //corresponding client code<br/> fwrite($client, "1234"); 

nel caso in cui il server del caso attenderà che si scriva un altro byte fwrite($client, "5");

Ti suggerisco di utilizzare semplicemente la function sleep($seconds) o anche la function usleep($nanoseconds) . Il timeout è impostato per lo stream stesso, non per each stream_get_contents