2016-12-21 3 views
4

Hinweis: Dieser Beitrag haben einen Unterschied mit diesem post, deren angenommene Antwort nur lesen Sie jede Zeile eine Zeit.Lesen der gesamten Ausgabe in Echtzeit im Stream

Ich muss 3D-Modelle für 3D-Druck auf der Serverseite schneiden, wird der Prozess einige Zeit kosten. Also muss ich den Prozess für den Benutzer zeigen, ich benutze die Redis um den Prozess zu speichern. Ich möchte den Prozess alle 0,5 Sekunden aktualisieren. Zum Beispiel schlafen 0,5 Sekunden, lesen Sie den gesamten Inhalt in der Pip und verarbeiten Sie es jedes Mal.

Für jetzt habe ich versucht, die unten zwei, die erste wird bis zum Ende halten. Die zweite Verwendung ist zwar kein richtiger Weg, aber es wird weiterhin die Redis schreiben, was dazu führen wird, dass die Client-Lese-Prozessanforderung bis zum Ende gehalten wird.

Ich habe diese tryed zwei:

Die erste wird halten, bis der Befehl beendet.

$descriptorspec = array(
    0 => array("pipe", "r"), 
    1 => array("pipe", "w"), 
    2 => array("pipe", "w") //here curaengine log all the info into stderror 
); 
$command = './CuraEngine slice -p -j ' . $fdmprinterpath . ' -j ' . $configpath . ' -o ' . $gcodepath . ' -l ' . $tempstlpath; 
$cwd = '/usr/local/curaengine'; 
$process = proc_open($command, $descriptorspec, $pipes, $cwd); 
if(is_resource($process)) 
{ 
    print stream_get_contents($pipes[1]); //This will hold until the command finished. 
} 

und die zweite als diese post implementiert wird jedes Mal einer Zeile.

$descriptorspec = array(
     0 => array("pipe", "r"), 
     1 => array("pipe", "w"), 
     2 => array("pipe", "w") //here curaengine log all the info into stderror 
    ); 
    $command = './CuraEngine slice -p -j ' . $fdmprinterpath . ' -j ' . $configpath . ' -o ' . $gcodepath . ' -l ' . $tempstlpath; 
    $cwd = '/usr/local/curaengine'; 
    $process = proc_open($command, $descriptorspec, $pipes, $cwd); 
    if(is_resource($process)) 
    { 
     while ($s = fgets($pipes[1])) { 
      print $s; 
      flush(); 
     } 
    } 
+0

Zeigt dies eine Art Fortschritt des Schneideprozesses? Welchen Client verwenden Sie? Ein Browser? – Rei

+0

@Ray Radin Ja, es ist ein Web-Cloud-Service, der Benutzer kann meinen Server verwenden, um 3D-Modelle zu schneiden, um Gcode für 3D-Druck zu erzeugen. Das erste Gerät gibt zum Abschlusszeitpunkt alles aus. Die Implementierung von secnod wird die Druckausgabe immer auf dem neuesten Stand halten. Aber wie die Frage sagt, möchte ich alle 0,5 Sekunden verarbeiten. –

+0

Ich habe einen Anwendungs-Deployer geschrieben, der eine Fortschrittsanzeige aktualisiert, um den Fortschritt der Bereitstellung anzuzeigen. Wenn Sie bereit sind, Ihren Ansatz etwas zu ändern, kann ich Ihnen eine abgespeckte Version als Beispiel zeigen. – Rei

Antwort

0

Verwendung fread() zu fgets() zu ersetzen.

1

Werfen Sie einen Blick auf die Symfony component Process. Es bietet unter anderem einfachen asynchronen Prozess und Echtzeit-Prozessausgabe. Zum Beispiel:

$process = new Process($command); 
$process->start('processOutput'); 

while ($process->isRunning()) { 
    usleep(500000); 
    $progress = $process->getIncrementalOutput(); 
    progressOutput($progress); 
} 

$output = $process->getOutput(); 

// 
// Example implementations: 
// 
function progressOutput($progress) {   
    echo $progress; 
    ob_flush(); 
} 

function processOutput($type, $output) { 
    if ($type == Process::OUT) { 
     echo $output; 
     ob_flush(); 
    } 
} 
1

sollten Sie die Ausgabe-Pufferung deaktivieren Sie bitte zuerst durch diese Linie zu Beginn des Codes hinzufügen:

while(@ob_end_clean()); 

Mit dieser Zeile hinzugefügt, Ihr zweiter Code sollte streamen kann.

Leider ist das Ergebnis der Ausgabe-Streaming auch bei deaktivierter Ausgabepufferung vom Browser abhängig. Ich habe mehrere Browser, Desktop und Mobile, getestet und festgestellt, dass Ausgabe Streaming in Chrom-basierten Browsern funktioniert, aber nicht in Firefox funktioniert.

Da es Browser-abhängig ist, sind die Funktionen, die Sie verwenden, egal ob fgets() oder fread(), irrelevant. Wenn Sie möchten, dass das Streaming auch in anderen Browsern funktioniert, können Sie es mit XMLHttpRequest kapseln. Hier

ist ein Beispiel, das mit Chrom-basierten Browsern funktioniert:

<?php 
//stream.php 

//disable output buffering 
while(@ob_end_clean()); 
ob_implicit_flush(true); 

if(empty($_SERVER['QUERY_STRING'])){ 
    //simulate a lengthy process 
    file_put_contents(__FILE__.'.txt',$z=''); 
    for($i=0; $i<10; $i++){ 
     sleep(1); 
     echo $s = "<div>{$i}</div>\n"; 
     file_put_contents(__FILE__.'.txt',$z.=$s); 
    } 
}else{ 
    //delay 500ms 
    usleep(500000); 
    echo file_get_contents(__FILE__.'.txt'); 
} 

Der HTML-Pendant macht es mit anderen Browsern:

<!DOCTYPE html> 
<html> 
<head><meta name="viewport" content="width=device-width, initial-scale=1" charset="utf-8"></head> 
<body> 
<div id='stream'></div> 
<script> 
var active = true; 
xhr('/stream.php',function(){ active = false; }); 
update(); 

function update(r){ 
    if(r) document.getElementById('stream').innerHTML = r.responseText; 
    if(active) xhr('/stream.php?stream',update); 
} 

function xhr(url,callback){ 
    var r = new XMLHttpRequest(); 
    r.open('GET',url); 
    r.onreadystatechange = function(){ if(r.readyState==4) callback(r); }; 
    r.send(); 
} 
</script> 
</body> 
</html> 

Sie können den gleichen Mechanismus verwenden, um einen Fortschritt zu schaffen Bar wie ich schon sagte.