2

正常に動作する小さな Socket.IO サーバーを作成しました。接続でき、メッセージを送受信できるので、すべて正常に動作しています。コードの関連部分のみをここに示します。

var RedisStore = require('socket.io/lib/stores/redis');
const pub = redis.createClient('127.0.0.1', 6379);
const sub = redis.createClient('127.0.0.1', 6379);
const store = redis.createClient('127.0.0.1', 6379); 

io.configure(function() {
  io.set('store', new RedisStore({
    redisPub    : pub, 
    redisSub    : sub, 
    redisClient : store
  }));
});

io.sockets.on('connection', function(socket) {
 socket.on('message', function(msg) {
    pub.publish("lobby", msg);
  });


  /*
   * Subscribe to the lobby and receive messages.
   */
  var sub = redis.createClient('127.0.0.1', 6379);
  sub.subscribe("lobby");
  sub.on('message', function(channel, msg) {
    socket.send(msg);
  });
});

サーバーに接続し、setInterval 関数で接続を生成する以下のスクリプトも作成しました。これは、10 ミリ秒ごとに新しい接続を生成するため、かなり多くの接続が生成されます。

#!/usr/bin/env node

var io = require('socket.io-client');
var reconn = {'force new connection': true};
var sockets = [];

var num = 1000;

function startSocket(i) {
  sockets[i] = io.connect("http://127.0.0.1:8080", reconn);
  sockets[i].on('connect', function() {
    console.log("Socket["+i+"] connected.");
  });
  sockets[i].on('message', function(msg) {
    console.log("Socket["+i+"] Message received: "+msg);
  });
}



/*
 * Start number of sockets.
 */
for(var i=0; i<num; i++) {
  startSocket(i);
}



/*
 * Send messages forever.
 */
setInterval(function() {
    for(var i=0; i<num; i++) {
      sockets[i].send("Hello from socket "+i+".");
    }
}, 10);

このスクリプトは、サーバーへの 1000 接続を生成するベンチマーク ツールですが、数分間実行すると、次のエラー メッセージが表示されてサーバーが停止します。

node.js:0 // 著作権は Joyent, Inc. およびその他のノード コントリビューターに帰属します。^ RangeError: 最大呼び出しスタック サイズを超えました

十分なスタック スペースがないため、例外が発生してプロセスが終了することはわかっていますが、 --stack-size 変数を使用してスタックを拡大しても、実際には問題は解決しません。これにより、最終的にサーバーが強制終了されます。

私の質問は、どうすればこれを防ぐことができるかです。これは効果的な DoS シナリオであり、誰でもこの小さなスクリプトをハッキングしてノード サーバーを強制的に終了させることができますが、私はこれが起こらないようにしたいと考えています。メッセージをゆっくりと処理するだけで、ノードサーバーが終了しないようにします。

これを防ぐことができるかどうかのアイデア。IP をブロックするかどうかはわかりません。多くの携帯電話が同じ IP を使用するシステムにログインするようにしたいので、ノード サーバーは DoS が 1 つだけ導入されていると誤って判断する可能性があります。モバイル ネットワークの動作を停止し、その IP をブロックします。

ありがとうございました

4

1 に答える 1

0

ノードサーバーを永久に実行したい場合は、https://github.com/nodejitsu/foreverを使用してください。

例外についてはvar sub = redis.createClient('127.0.0.1', 6379);、接続が確立されるたびにスタックに変数が割り当てられる可能性があると思います。

var subs = []私は最初にグローバルスコープ に入れようとし、subs[socket.id] = redis.createClient('127.0.0.1', 6379);

またはsocket.sub = redis.createClient('127.0.0.1', 6379);、既存の、できればヒープベースの socket.io データ構造をピギーバックするようなものです。

動作しない場合は、Redis の使用を削除して問題を切り分けてみてください...

于 2013-01-10T05:41:14.927 に答える