1

10msごとにクライアントにデータを繰り返し送信する次のコードがある場合:

setInterval(function() {
    res.write(somedata);
}, 10ms);

クライアントがデータを受信するのが非常に遅い場合はどうなりますか?

サーバーでメモリ不足エラーが発生しますか?

編集:実際には接続は維持され、サーバーはjpegデータを際限なく送信します(HTTPマルチパート/ x-mixed-replaceヘッダー+ボディ+ヘッダー+ボディ.....)
node.jsのresponse.writeは非同期で
あるため、一部のユーザーは推測しますデータを内部バッファーに保存し、低レイヤーが送信できることを通知するまで待機する可能性がある
ため、内部バッファーが大きくなります。

私が正しければ、これを解決するにはどうすればよいですか?
問題は、単一の書き込み呼び出しでデータが送信されたときに node.js が通知しないことです。

言い換えれば、この方法は理論的には「メモリ不足」のリスクがなく、それを修正する方法をユーザーに伝えることはできません。


更新: user568109 によって与えられたキーワード「drain」イベントによって、node.js のソースを調査し、結論を得ました:
それは本当に「メモリ不足」エラーを引き起こします。response.write(...)===false の戻り値を確認してから、応答の「ドレイン」イベントを処理する必要があります。

http.js:

OutgoingMessage.prototype._buffer = function(data, encoding) {
  this.output.push(data); //-------------No check here, will cause "out-of-memory"
  this.outputEncodings.push(encoding);

  return false;
};


OutgoingMessage.prototype._writeRaw = function(data, encoding) { //this will be called by resonse.write
  if (data.length === 0) {
    return true;
  }

  if (this.connection &&
      this.connection._httpMessage === this &&
      this.connection.writable &&
      !this.connection.destroyed) {
    // There might be pending data in the this.output buffer.
    while (this.output.length) {
      if (!this.connection.writable) {    //when not ready to send
        this._buffer(data, encoding);    //----------> save data into internal buffer
        return false;
      }
      var c = this.output.shift();
      var e = this.outputEncodings.shift();
      this.connection.write(c, e);
    }

    // Directly write to socket.
    return this.connection.write(data, encoding);
  } else if (this.connection && this.connection.destroyed) {
    // The socket was destroyed.  If we're still trying to write to it,
    // then we haven't gotten the 'close' event yet.
    return false;
  } else {
    // buffer, as long as we're not destroyed.
    this._buffer(data, encoding);
    return false;
  }
};
4

1 に答える 1

2

いくつかの落とし穴:

  1. http 経由で送信する場合は、お勧めできません。指定された時間内にリクエストが終了しない場合、ブラウザはリクエストをタイムアウトと見なす場合があります。サーバーも、アイドル状態が長すぎる接続を閉じます。クライアントが追いつかない場合、タイムアウトはほぼ確実です。

  2. 10ms の setInterval にもいくつかの制限があります。10 ミリ秒ごとに繰り返すという意味ではありません。10 ミリ秒は、繰り返す前に待機する最小値です。設定した間隔より遅くなります。

  3. 応答をデータでオーバーロードする可能性があるとしましょう。その後、ある時点でサーバーは接続を終了し413 Request Entity Too Large、設定されている制限に応じて応答します。

  4. Node.js には、最大メモリ制限が約 1.7 GB のシングル スレッド アーキテクチャがあります。上記のサーバー制限を高く設定しすぎて、多くの着信接続があると、process out of memoryエラーが発生します。

したがって、適切な制限を使用すると、タイムアウトが発生するか、リクエストが大きすぎます。(そして、プログラムに他のエラーはありません。)

アップデート

drainイベントを使用する必要があります。http 応答は書き込み可能なストリームです。独自の内部バッファがあります。バッファーが空になると、drain イベントがトリガーされます。ストリームについてもっと深く学ぶ必要があります。これは、httpだけでなく役立ちます。Web 上のストリームに関するいくつかのリソースを見つけることができます。

于 2014-07-23T09:31:53.123 に答える