mirror of
https://github.com/nodejs/node.git
synced 2024-11-21 10:59:27 +00:00
net: add new options to net.Socket
and net.Server
PR-URL: https://github.com/nodejs/node/pull/41310 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
This commit is contained in:
parent
c071bd581a
commit
45b5ca810a
@ -2865,6 +2865,16 @@ changes:
|
||||
[`--max-http-header-size`][] for requests received by this server, i.e.
|
||||
the maximum length of request headers in bytes.
|
||||
**Default:** 16384 (16 KB).
|
||||
* `noDelay` {boolean} If set to `true`, it disables the use of Nagle's
|
||||
algorithm immediately after a new incoming connection is received.
|
||||
**Default:** `false`.
|
||||
* `keepAlive` {boolean} If set to `true`, it enables keep-alive functionality
|
||||
on the socket immediately after a new incoming connection is received,
|
||||
similarly on what is done in \[`socket.setKeepAlive([enable][, initialDelay])`]\[`socket.setKeepAlive(enable, initialDelay)`].
|
||||
**Default:** `false`.
|
||||
* `keepAliveInitialDelay` {number} If set to a positive number, it sets the
|
||||
initial delay before the first keepalive probe is sent on an idle socket.
|
||||
**Default:** `0`.
|
||||
|
||||
* `requestListener` {Function}
|
||||
|
||||
@ -3108,6 +3118,8 @@ changes:
|
||||
* `callback` {Function}
|
||||
* Returns: {http.ClientRequest}
|
||||
|
||||
`options` in [`socket.connect()`][] are also supported.
|
||||
|
||||
Node.js maintains several connections per server to make HTTP requests.
|
||||
This function allows one to transparently issue requests.
|
||||
|
||||
|
@ -854,6 +854,14 @@ For TCP connections, available `options` are:
|
||||
`0` indicates that both IPv4 and IPv6 addresses are allowed. **Default:** `0`.
|
||||
* `hints` {number} Optional [`dns.lookup()` hints][].
|
||||
* `lookup` {Function} Custom lookup function. **Default:** [`dns.lookup()`][].
|
||||
* `noDelay` {boolean} If set to `true`, it disables the use of Nagle's algorithm immediately
|
||||
after the socket is established. **Default:** `false`.
|
||||
* `keepAlive` {boolean} If set to `true`, it enables keep-alive functionality on the socket
|
||||
immediately after the connection is established, similarly on what is done in
|
||||
[`socket.setKeepAlive([enable][, initialDelay])`][`socket.setKeepAlive(enable, initialDelay)`].
|
||||
**Default:** `false`.
|
||||
* `keepAliveInitialDelay` {number} If set to a positive number, it sets the initial delay before
|
||||
the first keepalive probe is sent on an idle socket.**Default:** `0`.
|
||||
|
||||
For [IPC][] connections, available `options` are:
|
||||
|
||||
@ -1415,8 +1423,18 @@ added: v0.5.0
|
||||
**Default:** `false`.
|
||||
* `pauseOnConnect` {boolean} Indicates whether the socket should be
|
||||
paused on incoming connections. **Default:** `false`.
|
||||
* `noDelay` {boolean} If set to `true`, it disables the use of Nagle's algorithm immediately
|
||||
after a new incoming connection is received. **Default:** `false`.
|
||||
* `keepAlive` {boolean} If set to `true`, it enables keep-alive functionality on the socket
|
||||
immediately after a new incoming connection is received, similarly on what is done in
|
||||
[`socket.setKeepAlive([enable][, initialDelay])`][`socket.setKeepAlive(enable, initialDelay)`].
|
||||
**Default:** `false`.
|
||||
* `keepAliveInitialDelay` {number} If set to a positive number, it sets the initial delay before
|
||||
the first keepalive probe is sent on an idle socket.**Default:** `0`.
|
||||
|
||||
* `connectionListener` {Function} Automatically set as a listener for the
|
||||
[`'connection'`][] event.
|
||||
|
||||
* Returns: {net.Server}
|
||||
|
||||
Creates a new TCP or [IPC][] server.
|
||||
@ -1582,6 +1600,7 @@ net.isIPv6('fhqwhgads'); // returns false
|
||||
[`socket.pause()`]: #socketpause
|
||||
[`socket.resume()`]: #socketresume
|
||||
[`socket.setEncoding()`]: #socketsetencodingencoding
|
||||
[`socket.setKeepAlive(enable, initialDelay)`]: #socketsetkeepaliveenable-initialdelay
|
||||
[`socket.setTimeout()`]: #socketsettimeouttimeout-callback
|
||||
[`socket.setTimeout(timeout)`]: #socketsettimeouttimeout-callback
|
||||
[`writable.destroy()`]: stream.md#writabledestroyerror
|
||||
|
@ -378,7 +378,11 @@ function Server(options, requestListener) {
|
||||
}
|
||||
|
||||
storeHTTPOptions.call(this, options);
|
||||
net.Server.call(this, { allowHalfOpen: true });
|
||||
net.Server.call(
|
||||
this,
|
||||
{ allowHalfOpen: true, noDelay: options.noDelay,
|
||||
keepAlive: options.keepAlive,
|
||||
keepAliveInitialDelay: options.keepAliveInitialDelay });
|
||||
|
||||
if (requestListener) {
|
||||
this.on('request', requestListener);
|
||||
|
73
lib/net.js
73
lib/net.js
@ -279,6 +279,8 @@ function initSocketHandle(self) {
|
||||
const kBytesRead = Symbol('kBytesRead');
|
||||
const kBytesWritten = Symbol('kBytesWritten');
|
||||
const kSetNoDelay = Symbol('kSetNoDelay');
|
||||
const kSetKeepAlive = Symbol('kSetKeepAlive');
|
||||
const kSetKeepAliveInitialDelay = Symbol('kSetKeepAliveInitialDelay');
|
||||
|
||||
function Socket(options) {
|
||||
if (!(this instanceof Socket)) return new Socket(options);
|
||||
@ -297,6 +299,15 @@ function Socket(options) {
|
||||
'is not supported'
|
||||
);
|
||||
}
|
||||
if (typeof options?.keepAliveInitialDelay !== 'undefined') {
|
||||
validateNumber(
|
||||
options?.keepAliveInitialDelay, 'options.keepAliveInitialDelay'
|
||||
);
|
||||
|
||||
if (options.keepAliveInitialDelay < 0) {
|
||||
options.keepAliveInitialDelay = 0;
|
||||
}
|
||||
}
|
||||
|
||||
this.connecting = false;
|
||||
// Problem with this is that users can supply their own handle, that may not
|
||||
@ -307,7 +318,6 @@ function Socket(options) {
|
||||
this[kHandle] = null;
|
||||
this._parent = null;
|
||||
this._host = null;
|
||||
this[kSetNoDelay] = false;
|
||||
this[kLastWriteQueueSize] = 0;
|
||||
this[kTimeout] = null;
|
||||
this[kBuffer] = null;
|
||||
@ -381,6 +391,10 @@ function Socket(options) {
|
||||
this[kBufferCb] = onread.callback;
|
||||
}
|
||||
|
||||
this[kSetNoDelay] = Boolean(options.noDelay);
|
||||
this[kSetKeepAlive] = Boolean(options.keepAlive);
|
||||
this[kSetKeepAliveInitialDelay] = ~~(options.keepAliveInitialDelay / 1000);
|
||||
|
||||
// Shut down the socket when we're finished with it.
|
||||
this.on('end', onReadableStreamEnd);
|
||||
|
||||
@ -504,31 +518,38 @@ Socket.prototype._onTimeout = function() {
|
||||
|
||||
|
||||
Socket.prototype.setNoDelay = function(enable) {
|
||||
// Backwards compatibility: assume true when `enable` is omitted
|
||||
enable = Boolean(enable === undefined ? true : enable);
|
||||
|
||||
if (!this._handle) {
|
||||
this.once('connect',
|
||||
enable ? this.setNoDelay : () => this.setNoDelay(enable));
|
||||
this[kSetNoDelay] = enable;
|
||||
return this;
|
||||
}
|
||||
|
||||
// Backwards compatibility: assume true when `enable` is omitted
|
||||
const newValue = enable === undefined ? true : !!enable;
|
||||
if (this._handle.setNoDelay && newValue !== this[kSetNoDelay]) {
|
||||
this[kSetNoDelay] = newValue;
|
||||
this._handle.setNoDelay(newValue);
|
||||
if (this._handle.setNoDelay && enable !== this[kSetNoDelay]) {
|
||||
this[kSetNoDelay] = enable;
|
||||
this._handle.setNoDelay(enable);
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
Socket.prototype.setKeepAlive = function(setting, msecs) {
|
||||
Socket.prototype.setKeepAlive = function(enable, initialDelayMsecs) {
|
||||
enable = Boolean(enable);
|
||||
const initialDelay = ~~(initialDelayMsecs / 1000);
|
||||
|
||||
if (!this._handle) {
|
||||
this.once('connect', () => this.setKeepAlive(setting, msecs));
|
||||
this[kSetKeepAlive] = enable;
|
||||
this[kSetKeepAliveInitialDelay] = initialDelay;
|
||||
return this;
|
||||
}
|
||||
|
||||
if (this._handle.setKeepAlive)
|
||||
this._handle.setKeepAlive(setting, ~~(msecs / 1000));
|
||||
if (this._handle.setKeepAlive && enable !== this[kSetKeepAlive]) {
|
||||
this[kSetKeepAlive] = enable;
|
||||
this[kSetKeepAliveInitialDelay] = initialDelay;
|
||||
this._handle.setKeepAlive(enable, initialDelay);
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
@ -1141,6 +1162,14 @@ function afterConnect(status, handle, req, readable, writable) {
|
||||
}
|
||||
self._unrefTimer();
|
||||
|
||||
if (self[kSetNoDelay] && self._handle.setNoDelay) {
|
||||
self._handle.setNoDelay(true);
|
||||
}
|
||||
|
||||
if (self[kSetKeepAlive] && self._handle.setKeepAlive) {
|
||||
self._handle.setKeepAlive(true, self[kSetKeepAliveInitialDelay]);
|
||||
}
|
||||
|
||||
self.emit('connect');
|
||||
self.emit('ready');
|
||||
|
||||
@ -1204,6 +1233,15 @@ function Server(options, connectionListener) {
|
||||
} else {
|
||||
throw new ERR_INVALID_ARG_TYPE('options', 'Object', options);
|
||||
}
|
||||
if (typeof options.keepAliveInitialDelay !== 'undefined') {
|
||||
validateNumber(
|
||||
options.keepAliveInitialDelay, 'options.keepAliveInitialDelay'
|
||||
);
|
||||
|
||||
if (options.keepAliveInitialDelay < 0) {
|
||||
options.keepAliveInitialDelay = 0;
|
||||
}
|
||||
}
|
||||
|
||||
this._connections = 0;
|
||||
|
||||
@ -1215,6 +1253,9 @@ function Server(options, connectionListener) {
|
||||
|
||||
this.allowHalfOpen = options.allowHalfOpen || false;
|
||||
this.pauseOnConnect = !!options.pauseOnConnect;
|
||||
this.noDelay = Boolean(options.noDelay);
|
||||
this.keepAlive = Boolean(options.keepAlive);
|
||||
this.keepAliveInitialDelay = ~~(options.keepAliveInitialDelay / 1000);
|
||||
}
|
||||
ObjectSetPrototypeOf(Server.prototype, EventEmitter.prototype);
|
||||
ObjectSetPrototypeOf(Server, EventEmitter);
|
||||
@ -1567,6 +1608,14 @@ function onconnection(err, clientHandle) {
|
||||
writable: true
|
||||
});
|
||||
|
||||
if (self.noDelay && handle.setNoDelay) {
|
||||
handle.setNoDelay(true);
|
||||
}
|
||||
|
||||
if (self.keepAlive && self.setKeepAlive) {
|
||||
handle.setKeepAlive(true, handle.keepAliveInitialDelay);
|
||||
}
|
||||
|
||||
self._connections++;
|
||||
socket.server = self;
|
||||
socket._server = self;
|
||||
|
56
test/parallel/test-net-connect-keepalive.js
Normal file
56
test/parallel/test-net-connect-keepalive.js
Normal file
@ -0,0 +1,56 @@
|
||||
'use strict';
|
||||
|
||||
const common = require('../common');
|
||||
const assert = require('assert');
|
||||
const net = require('net');
|
||||
|
||||
const truthyValues = [true, 1, 'true', {}, []];
|
||||
const delays = [[123, 0], [456123, 456], [-123000, 0], [undefined, 0]];
|
||||
const falseyValues = [false, 0, ''];
|
||||
|
||||
const genSetKeepAlive = (desiredEnable, desiredDelay) => (enable, delay) => {
|
||||
assert.strictEqual(enable, desiredEnable);
|
||||
assert.strictEqual(delay, desiredDelay);
|
||||
};
|
||||
|
||||
for (const value of truthyValues) {
|
||||
for (const delay of delays) {
|
||||
const server = net.createServer();
|
||||
|
||||
server.listen(0, common.mustCall(function() {
|
||||
const port = server.address().port;
|
||||
|
||||
const client = net.connect(
|
||||
{ port, keepAlive: value, keepAliveInitialDelay: delay[0] },
|
||||
common.mustCall(() => client.end())
|
||||
);
|
||||
|
||||
client._handle.setKeepAlive = common.mustCall(
|
||||
genSetKeepAlive(true, delay[1])
|
||||
);
|
||||
|
||||
client.on('end', common.mustCall(function() {
|
||||
server.close();
|
||||
}));
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
for (const value of falseyValues) {
|
||||
const server = net.createServer();
|
||||
|
||||
server.listen(0, common.mustCall(function() {
|
||||
const port = server.address().port;
|
||||
|
||||
const client = net.connect(
|
||||
{ port, keepAlive: value },
|
||||
common.mustCall(() => client.end())
|
||||
);
|
||||
|
||||
client._handle.setKeepAlive = common.mustNotCall();
|
||||
|
||||
client.on('end', common.mustCall(function() {
|
||||
server.close();
|
||||
}));
|
||||
}));
|
||||
}
|
49
test/parallel/test-net-connect-nodelay.js
Normal file
49
test/parallel/test-net-connect-nodelay.js
Normal file
@ -0,0 +1,49 @@
|
||||
'use strict';
|
||||
|
||||
const common = require('../common');
|
||||
const assert = require('assert');
|
||||
const net = require('net');
|
||||
|
||||
const truthyValues = [true, 1, 'true', {}, []];
|
||||
const falseyValues = [false, 0, ''];
|
||||
const genSetNoDelay = (desiredArg) => (enable) => {
|
||||
assert.strictEqual(enable, desiredArg);
|
||||
};
|
||||
|
||||
for (const value of truthyValues) {
|
||||
const server = net.createServer();
|
||||
|
||||
server.listen(0, common.mustCall(function() {
|
||||
const port = server.address().port;
|
||||
|
||||
const client = net.connect(
|
||||
{ port, noDelay: value },
|
||||
common.mustCall(() => client.end())
|
||||
);
|
||||
|
||||
client._handle.setNoDelay = common.mustCall(genSetNoDelay(true));
|
||||
|
||||
client.on('end', common.mustCall(function() {
|
||||
server.close();
|
||||
}));
|
||||
}));
|
||||
}
|
||||
|
||||
for (const value of falseyValues) {
|
||||
const server = net.createServer();
|
||||
|
||||
server.listen(0, common.mustCall(function() {
|
||||
const port = server.address().port;
|
||||
|
||||
const client = net.connect(
|
||||
{ port, noDelay: value },
|
||||
common.mustCall(() => client.end())
|
||||
);
|
||||
|
||||
client._handle.setNoDelay = common.mustNotCall();
|
||||
|
||||
client.on('end', common.mustCall(function() {
|
||||
server.close();
|
||||
}));
|
||||
}));
|
||||
}
|
Loading…
Reference in New Issue
Block a user