次の子を生成しました:var spw = spawn('ping', ['-n','10', '127.0.0.1'])
そしてクライアント側でpingの結果を受け取りたい(browser)全体ではなく、1つずつ。
これまで私はこれを試しました:
app.get('/path', function(req, res) {
...
spw.stdout.on('data', function (data) {
var str = data.toString();
res.write(str + "\n");
});
...
}
そしてそれ:
...
spw.stdout.pipe(res);
...
どちらの場合も、ブラウザは10回のpingが完了するのを待ってから、結果全体を出力します。一つずつ持っていきたいのですが、どうやってそれを実現するのですか?
(クライアントは.../path
を呼び出しているだけで、console.logsの結果が記録されます)
EDIT:これを実装するにはWebSocketが必要だと思いますが、他に方法があるかどうかを知りたいだけです。いくつかの紛らわしい SO回答 とブログ投稿( this 投稿で、ステップ1のOPがログをブラウザにストリーミングする)を見たので、役に立たなかったので、いくつかの注意のために賞金を取りに行きます。
SSE(サーバー送信イベント)を使用した完全な例を次に示します。これはFirefoxで機能し、おそらくChromeも:
var cp = require("child_process"),
express = require("express"),
app = express();
app.configure(function(){
app.use(express.static(__dirname));
});
app.get('/msg', function(req, res){
res.writeHead(200, { "Content-Type": "text/event-stream",
"Cache-control": "no-cache" });
var spw = cp.spawn('ping', ['-c', '100', '127.0.0.1']),
str = "";
spw.stdout.on('data', function (data) {
str += data.toString();
// just so we can see the server is doing something
console.log("data");
// Flush out line by line.
var lines = str.split("\n");
for(var i in lines) {
if(i == lines.length - 1) {
str = lines[i];
} else{
// Note: The double-newline is *required*
res.write('data: ' + lines[i] + "\n\n");
}
}
});
spw.on('close', function (code) {
res.end(str);
});
spw.stderr.on('data', function (data) {
res.end('stderr: ' + data);
});
});
app.listen(4000);
そしてクライアントHTML:
<!DOCTYPE Html>
<html>
<body>
<ul id="eventlist"> </ul>
<script>
var eventList = document.getElementById("eventlist");
var evtSource = new EventSource("http://localhost:4000/msg");
var newElement = document.createElement("li");
newElement.innerHTML = "Messages:";
eventList.appendChild(newElement);
evtSource.onmessage = function(e) {
console.log("received event");
console.log(e);
var newElement = document.createElement("li");
newElement.innerHTML = "message: " + e.data;
eventList.appendChild(newElement);
};
evtSource.onerror = function(e) {
console.log("EventSource failed.");
};
console.log(evtSource);
</script>
</body>
</html>
node index.js
を実行し、ブラウザでhttp://localhost:4000/client.html
を指定します。 OS Xを実行しているので、「-n」ではなく「-c」オプションを使用する必要があることに注意してください。
Google Chromeを使用している場合は、コンテンツタイプを「text/event-stream」に変更すると、探しているものが実行されます。
res.writeHead(200, { "Content-Type": "text/event-stream" });
完全な例については、私の要点を参照してください: https://Gist.github.com/sfarthin/91395
これは、標準のHTTP要求/応答サイクルでは実現できません。基本的にあなたがやろうとしていることは、「プッシュ」または「リアルタイム」サーバーを作ることです。これは、xhr-pollingまたはwebsocketでのみ実現できます。
_app.get('/path', function(req, res) {
...
spw.stdout.on('data', function (data) {
var str = data.toString();
res.write(str + "\n");
});
...
}
_
このコードは終了信号を送信しないため、応答しません。そのイベントハンドラー内でres.end()
への呼び出しを追加した場合、最初のpingのみが取得されます。これは、stdoutからのデータの最初のチャンクの後に応答ストリームを終了するため、予期される動作です。
_spw.stdout.pipe(res);
_
ここで、stdoutはパケットをブラウザにフラッシュしていますが、ブラウザはすべてのパケットが受信されるまでデータチャンクをレンダリングしません。したがって、10秒間待機してから、stdout全体をレンダリングする理由。この方法の主な利点は、送信前に応答をメモリにバッファリングしないことです。つまり、メモリフットプリントを軽量に保つことができます。