我写了一个小的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函数中生成连接,每个10milisecons产生一个新连接,因此它产生了很多连接。
#!/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。和其他Node贡献者。 ^ RangeError:超出最大调用堆栈大小
我知道没有足够的堆栈空间可用,因此异常发生并且进程终止,但即使我使用--stack-size变量扩大堆栈,这实际上并没有解决问题,因为我可以总是产生更多的连接,最终会杀死服务器。
我的问题是:如何防止这种情况发生。这是一个有效的DoS场景,任何人都可以将这个小脚本组合在一起并强制节点服务器终止,但我想防止这种情况发生。我希望Node服务器永远不会终止,只是慢慢处理消息。
任何想法,如果这可以防止。我不确定我是否想要阻止IP,因为我还希望手机登录到系统,其中许多人使用相同的IP,因此节点服务器可能错误地认为DoS正在由一个移动网络运营并阻止其IP。
谢谢
答案 0 :(得分: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的使用来隔离问题......