J'ai écrit un script de relais simple qui se connecte à une caméra Web et lit à partir de la prise et génère ces données à l'aide de la fonction d'impression. Les données sont des données MJPG avec des limites déjà configurées. Je viens de sortir les données lues.
Le problème est PHP semble mettre ces données en mémoire tampon. Lorsque je règle la caméra sur 1 FPS, le flux se fige pendant 7 à 8 secondes, puis affiche rapidement 8 images. Si je règle la résolution à une taille énorme, la caméra se déplace à plus ou moins 1 image par seconde. Je suppose alors qu'une certaine mise en mémoire tampon se produit (car les tailles énormes remplissent le tampon rapidement, et les tailles faibles ne le font pas), et je ne peux pas comprendre comment désactiver cette mise en mémoire tampon. Quelqu'un sait-il comment le faire?
Code:
ignore_user_abort(false);
$boundary = "myboundary";
//Set this so PHP doesn't timeout during a long stream
set_time_limit(0);
$socketConn = @fsockopen ("192.168.1.6", 1989, $errno, $errstr, 2);
if (!$socketConn)
exit();
stream_set_timeout($socketConn, 10);
fputs ($socketConn, "GET /mjpeg HTTP/1.0\r\n\r\n");
//Setup Header Information
header("Cache-Control: no-cache");
header("Cache-Control: private");
header("Pragma: no-cache");
header("Content-type: multipart/x-mixed-replace; boundary=$boundary");
@ini_set('implicit_flush', 1);
for ($i = 0; $i < ob_get_level(); $i++)
ob_end_flush();
ob_implicit_flush(1);
stream_set_blocking($f2, false);
//Send data to client
while (connection_status() == CONNECTION_NORMAL)
{
$chunk = fread($socketConn, 128);
print $chunk;
}
fclose($socketConn);
Faites deux choses:
Désactivez le tampon de sortie de l'espace utilisateur, soit ...
Globalement, soit par ...
output_buffering
Dans votre php.ini, ouDésactiver output_buffering
Dans votre configuration Apache à l'aide de
php_flag "output_buffering" Off
ou juste pour le script qui vous intéresse, soit par ...
ob_end_flush()
, ouob_end_clean()
De plus, désactivez le tampon de sortie au niveau du serveur autant que possible, soit:
ob_implicit_flush()
au début de votre script, ouflush()
après chaque echo
instruction ou autre instruction qui ajoute une sortie au corps de la réponseDe façon confuse, il existe deux couches de mise en mémoire tampon qui peuvent être pertinentes et la documentation PHP fait une mauvaise distinction entre les deux.
La première couche est généralement désignée par les documents PHP comme "tampon de sortie". Cette couche de mise en mémoire tampon affecte uniquement la sortie vers le corps de la réponse HTTP , pas les en-têtes. Vous pouvez activer la mise en mémoire tampon de sortie avec ob_start()
, et la désactiver avec ob_end_flush()
ou ob_end_clean()
. Vous pouvez également faire démarrer automatiquement tous vos scripts avec une mise en mémoire tampon de sortie en utilisant l'option output_buffering
dans php.ini.
La valeur par défaut de cette option pour versions de production de php.ini est 4096, ce qui signifie que les 4096 premiers octets de sortie seront mis en mémoire tampon dans le tampon de sortie, point auquel il sera vidé et mis en tampon de sortie est désactivé.
Vous pouvez désactiver cette couche de mise en mémoire tampon globalement en définissant output_buffering
Sur Off
dans votre fichier php.ini (ou en utilisant
php_flag "output_buffering" Off
dans votre configuration Apache, si vous utilisez Apache). Vous pouvez également le désactiver pour un seul script en appelant ob_end_clean()
ou ob_end_flush()
au début du script.
Au-delà du tampon de sortie se trouve ce que le manuel PHP se réfère au "tampon d'écriture", plus tout système de tampon de votre serveur Web. Si vous utilisez PHP = avec Apache via mod_php
, et n'utilisez pas mod_gzip
, vous pouvez appeler flush()
pour les vider; avec d'autres backends, cela pourrait fonctionner aussi, bien que le manuel soit hésitant à donner des assurances:
La description
void flush ( void )
Vide les tampons d'écriture de PHP et quel que soit le backend PHP utilise (CGI, un serveur Web, etc.). Cela tente de pousser la sortie actuelle jusqu'à le navigateur avec quelques mises en garde.
flush () peut ne pas être en mesure de remplacer le schéma de mise en mémoire tampon de votre serveur Web et il n'a aucun effet sur la mise en mémoire tampon côté client dans le navigateur. Cela n'affecte pas non plus le mécanisme de mise en mémoire tampon de sortie de l'espace utilisateur de PHP. Cela signifie que vous devrez appeler à la fois ob_flush () et flush () pour vider les tampons de sortie ob si vous utilisez ceux.
Il y a aussi quelques façons de faire PHP appeler automatiquement flush()
chaque fois que vous echo
quoi que ce soit (ou faire autre chose qui fait écho à la sortie de la réponse) corps).
La première consiste à appeler ob_implicit_flush()
. Notez que cette fonction porte un nom trompeur; étant donné son préfixe ob_
, toute personne raisonnable s'attendrait à ce que cela affecte le "tampon de sortie", tout comme ob_start
, ob_flush
etc. Cependant, ce n'est pas le cas; ob_implicit_flush()
, comme flush()
, affecte le tampon de sortie au niveau du serveur et n'interagit en aucune façon avec le tampon de sortie contrôlé par les autres fonctions ob_
.
La seconde consiste à activer globalement le vidage implicite en définissant le drapeau implicit_flush
sur On
dans votre php.ini. Cela revient à appeler ob_implicit_flush()
au début de chaque script. Notez que le manuel déconseille cela, citant cryptiquement "implications sérieuses en termes de performances", dont j'explore certaines dans ce réponse liée de manière tangentielle .
Plutôt que de désactiver la mise en mémoire tampon de sortie, vous pouvez simplement appeler flush()
après chaque opération de lecture. Cela évite d'avoir à jouer avec la configuration du serveur et rend votre script plus portable.
La mise en mémoire tampon de sortie peut être superposée et j'ai eu des cas où le code précédent avait fait plusieurs niveaux. Cela les effacera tous.
while (ob_get_level()) ob_end_clean();
// or ob_end_flush() if you want the contents of the buffer.
Nous pouvons donner le code ci-dessous dans le fichier .htaccess pour désactiver la mise en mémoire tampon de sortie en PHP
php_flag "output_buffering" off
Je sais que cette question est un peu ancienne, mais pour en revenir à cette question, vous pouvez désactiver la mise en mémoire tampon de sortie script par script, comme ceci:
if (ob_get_level())
ob_end_clean();
Cela devrait désactiver tous les tampons de sortie pour tout script qui le suit.