mirror of https://github.com/nodejs/node.git
parent
cde80d9859
commit
4593c04959
|
@ -2196,6 +2196,15 @@ Stops the server from accepting new connections. This function is
|
|||
asynchronous, the server is finally closed when the server emits a `'close'`
|
||||
event.
|
||||
|
||||
### server.maxConnections
|
||||
|
||||
Set this property to reject connections when the server's connection count gets high.
|
||||
|
||||
### server.connections
|
||||
|
||||
The number of concurrent connections on the server.
|
||||
|
||||
|
||||
|
||||
## net.Stream
|
||||
|
||||
|
|
47
lib/net.js
47
lib/net.js
|
@ -220,29 +220,6 @@ var ioWatchers = new FreeList("iowatcher", 100, function () {
|
|||
});
|
||||
|
||||
|
||||
// waitingForFDs stores servers which have experienced EMFILE.
|
||||
// When a file descriptor becomes available through closeFD()
|
||||
// a server from waitingForFDs is started.
|
||||
|
||||
var waitingForFDs = [];
|
||||
|
||||
function closeFD(fd) {
|
||||
close(fd);
|
||||
|
||||
// Try to recover from EMFILE
|
||||
|
||||
var server, serverFD;
|
||||
while (server = waitingForFDs.shift()) {
|
||||
serverFD = parseInt(server.fd);
|
||||
if (serverFD && serverFD > 0) {
|
||||
server.watcher.set(serverFD, true, false);
|
||||
server.watcher.start();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Allocated on demand.
|
||||
var pool = null;
|
||||
function allocNewPool () {
|
||||
|
@ -997,9 +974,13 @@ Stream.prototype.destroy = function (exception) {
|
|||
this.secureStream.close();
|
||||
}
|
||||
|
||||
if (this.server) {
|
||||
this.server.connections--;
|
||||
}
|
||||
|
||||
// FIXME Bug when this.fd == 0
|
||||
if (typeof this.fd == 'number') {
|
||||
closeFD(this.fd);
|
||||
close(this.fd);
|
||||
this.fd = null;
|
||||
process.nextTick(function () {
|
||||
if (exception) self.emit('error', exception);
|
||||
|
@ -1058,6 +1039,8 @@ function Server (listener) {
|
|||
self.addListener('connection', listener);
|
||||
}
|
||||
|
||||
self.connections = 0;
|
||||
|
||||
self.watcher = new IOWatcher();
|
||||
self.watcher.host = self;
|
||||
self.watcher.callback = function () {
|
||||
|
@ -1065,15 +1048,19 @@ function Server (listener) {
|
|||
try {
|
||||
var peerInfo = accept(self.fd);
|
||||
} catch (e) {
|
||||
if (e.errno == EMFILE) {
|
||||
waitingForFDs.push(self);
|
||||
self.watcher.stop();
|
||||
return;
|
||||
}
|
||||
if (e.errno == EMFILE) return;
|
||||
throw e;
|
||||
}
|
||||
if (!peerInfo) return;
|
||||
|
||||
if (self.maxConnections && self.connections >= self.maxConnections) {
|
||||
// Accept and close the connection.
|
||||
close(peerInfo.fd);
|
||||
return;
|
||||
}
|
||||
|
||||
self.connections++;
|
||||
|
||||
var s = new Stream(peerInfo.fd, self.type);
|
||||
s.remoteAddress = peerInfo.address;
|
||||
s.remotePort = peerInfo.port;
|
||||
|
@ -1209,7 +1196,7 @@ Server.prototype.close = function () {
|
|||
|
||||
self.watcher.stop();
|
||||
|
||||
closeFD(self.fd);
|
||||
close(self.fd);
|
||||
self.fd = null;
|
||||
|
||||
if (self.type === "unix") {
|
||||
|
|
|
@ -13,6 +13,7 @@ function pingPongTest (port, host) {
|
|||
var server = net.createServer(function (socket) {
|
||||
console.log("connection: " + socket.remoteAddress);
|
||||
assert.equal(server, socket.server);
|
||||
assert.equal(1, server.connections);
|
||||
|
||||
socket.setNoDelay();
|
||||
socket.timeout = 0;
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
common = require("../common");
|
||||
assert = common.assert;
|
||||
net = require('net');
|
||||
|
||||
// This test creates 200 connections to a server and sets the server's
|
||||
// maxConnections property to 100. The first 100 connections make it through
|
||||
// and the last 100 connections are rejected.
|
||||
// TODO: test that the server can accept more connections after it reaches
|
||||
// its maximum and some are closed.
|
||||
|
||||
N = 200;
|
||||
count = 0;
|
||||
closes = 0;
|
||||
waits = [];
|
||||
|
||||
server = net.createServer(function (connection) {
|
||||
console.error("connect %d", count++);
|
||||
connection.write("hello");
|
||||
waits.push(function () { connection.end(); });
|
||||
});
|
||||
|
||||
server.listen(common.PORT, function () {
|
||||
for (var i = 0; i < N; i++) {
|
||||
makeConnection(i);
|
||||
}
|
||||
});
|
||||
|
||||
server.maxConnections = N/2;
|
||||
|
||||
console.error("server.maxConnections = %d", server.maxConnections);
|
||||
|
||||
|
||||
function makeConnection (index) {
|
||||
setTimeout(function () {
|
||||
var c = net.createConnection(common.PORT);
|
||||
var gotData = false;
|
||||
|
||||
c.on('end', function () { c.end(); });
|
||||
|
||||
c.on('data', function (b) {
|
||||
gotData = true;
|
||||
assert.ok(0 < b.length);
|
||||
});
|
||||
|
||||
c.on('error', function (e) {
|
||||
console.error("error %d: %s", index, e);
|
||||
});
|
||||
|
||||
c.on('close', function () {
|
||||
console.error("closed %d", index);
|
||||
closes++;
|
||||
|
||||
if (closes < N/2) {
|
||||
assert.ok(server.maxConnections <= index,
|
||||
index + " was one of the first closed connections but shouldnt have been");
|
||||
}
|
||||
|
||||
if (closes === N/2) {
|
||||
var cb;
|
||||
console.error("calling wait callback.");
|
||||
while (cb = waits.shift()) {
|
||||
cb();
|
||||
}
|
||||
server.close();
|
||||
}
|
||||
|
||||
if (index < server.maxConnections) {
|
||||
assert.equal(true, gotData, index + " didn't get data, but should have");
|
||||
} else {
|
||||
assert.equal(false, gotData, index + " got data, but shouldn't have");
|
||||
}
|
||||
});
|
||||
}, index);
|
||||
}
|
||||
|
||||
|
||||
process.on('exit', function () {
|
||||
assert.equal(N, closes);
|
||||
});
|
Loading…
Reference in New Issue