Comment désactiver la mémoire tampon de sortie en PHP

j'ai écrit un script de relais simple qui se connecte à une caméra web et lit à partir de la socket, et sort ces données en utilisant la fonction d'impression. Les données sont des données MJPG avec des limites déjà établies. Je sors juste les données qui sont lues.

le problème est que PHP semble mettre ces données en tampon. Quand je mets la caméra à 1 FPS, le flux va geler pendant 7-8 secondes, puis afficher rapidement 8 images. Si je mets la résolution à une taille énorme, la caméra se déplace à plus ou moins 1 image par seconde. Je suppose qu'il se produit alors un certain buffering (puisque les tailles énormes remplissent le buffer rapidement, et les tailles basses ne le font pas), et je ne peux pas comprendre comment désactiver ce buffering. Personne ne sait comment?

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.0rnrn");

//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);
24
demandé sur Ioncannon 2012-01-16 19:43:16

5 réponses

tl;dr version

faire deux choses:

  1. désactivez le tampon de sortie de l'espace utilisateur, soit...

    • globalement, par l'un ou l'autre...

      • mise hors tension output_buffering dans votre php.ini, ou
      • désactiver output_buffering dans votre configuration Apache en utilisant

        php_flag "output_buffering" Off
        
    • ou pour le script qui vous intéresse, par l'un ou l'autre...

      • appelant ob_end_flush() , ou
      • appelant ob_end_clean()
  2. désactivez aussi le tampon de sortie au niveau du serveur autant que vous le pouvez, soit par:

    • appelant ob_implicit_flush() au début de votre script, ou
    • appelant flush() après chaque déclaration echo ou toute autre déclaration qui ajoute une sortie au corps de réponse

version longue

de manière confuse, il y a deux couches de tampon qui peuvent être pertinentes et la documentation PHP fait un mauvais travail de distinction entre les deux.

le tampon de sortie

La première couche est généralement désigné par les docs PHP comme le "tampon de sortie". Cette couche de buffering n'affecte que la sortie vers le corps de la réponse HTTP, pas les en-têtes. Vous pouvez activer le tampon de sortie ob_start() , et l'éteindre avec ob_end_flush() ou ob_end_clean() . Vous pouvez également faire démarrer tous vos scripts automatiquement avec la mise en mémoire tampon de sortie en utilisant le output_buffering option en php.ini.

la valeur par défaut de cette option pour les versions de production de php.ini est 4096, ce qui signifie que les premiers 4096 octets de sortie sera tamponné dans le tampon de sortie, à quel point il sera rincé et le tampon de sortie est éteint.

vous pouvez désactiver cette couche de buffering globalement en paramétrant output_buffering à Off dans votre php.fichier ini (ou en utilisant

php_flag "output_buffering" Off

dans votre configuration Apache, si vous utilisez Apache). Alternativement, vous pouvez la désactiver pour un seul script, en appelant ob_end_clean() ou ob_end_flush() au début du script.

La mémoire tampon d'écriture, et le serveur web tampon

au-delà du tampon de sortie est ce que le manuel PHP appelle le "tampon d'écriture", plus tout système de buffering que votre serveur web possède. Si vous utilisez PHP avec Apache à travers mod_php , et ne sont pas en utilisant mod_gzip , vous pouvez appeler flush() pour rincer ceux-ci; avec d'autres maux de dos, il pourrait fonctionner aussi, bien que le manuel est méfiant au sujet de donner des assurances:

Description

void flush ( void )

élimine les tampons d'écriture de PHP et de tout ce que backend PHP utilise (CGI, un serveur web, etc.). Cela tente de pousser la sortie actuelle jusqu'au navigateur avec quelques mises en garde.

flush() peut ne pas être en mesure de remplacer le tampon de régime de votre serveur web et il n'a pas d'effet sur le côté client de la mémoire dans le navigateur. Il n'affecte pas non plus le mécanisme de tampon de sortie de L'espace utilisateur de PHP. Cela signifie que vous devrez appeler à la fois ob_flush() et flush() pour rincer les tampons de sortie ob si vous les utilisez.

Il ya aussi un couple de vous pouvez faire appel à PHP automatiquement flush() chaque fois que vous echo n'importe quoi (ou faire n'importe quoi d'autre qui fait écho à la sortie au corps de réponse).

le premier est d'appeler ob_implicit_flush() . Notez que cette fonction est nommée de façon trompeuse; étant donné son préfixe ob_ , toute personne raisonnable s'attendrait à ce qu'elle affecte le "tampon de sortie", comme le font 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_ .

le second est d'activer globalement le rinçage implicite en positionnant le drapeau implicit_flush à On dans votre php.ini. Cela équivaut à appeler ob_implicit_flush() au début de chaque script. Notez que le manuel déconseille cela, citant cryptiquement " grave performance implications" , dont j'explore quelques-unes dans cette réponse tangentiellement liée .

44
répondu Mark Amery 2017-09-27 20:34:36

plutôt que de désactiver le tampon de sortie, vous pouvez simplement appeler flush() après chaque opération de lecture. Cela évite d'avoir à modifier la configuration du serveur et rend votre script plus portable.

17
répondu DaveRandom 2012-01-16 15:46:44

tampon de sortie peut être stratifié et j'ai eu des cas où le code antérieur avait fait plusieurs niveaux. Cela permettra d'effacer tous les.

while (ob_get_level()) ob_end_clean(); 
// or ob_end_flush() if you want the contents of the buffer.
3
répondu Yehosef 2016-10-26 08:38:47

nous pouvons donner le code ci-dessous dans le .htaccess pour désactiver le tampon de sortie en PHP

php_flag "output_buffering" off
2
répondu Binod 2013-06-05 12:29:24

je sais que cette question est un peu vieille, mais pour revenir à cette question, vous pouvez désactiver la mémoire tampon de sortie sur une base de script à script, comme ceci:

if (ob_get_level())
   ob_end_clean();

ceci devrait désactiver toute mise en mémoire tampon de sortie pour tout script qui le suit.

0
répondu Solomon Closson 2014-04-30 15:41:35