Skip to content

Commit 137f53c

Browse files
committed
dgram: support dgram.send with multiple buffers
Added ability to dgram.send to send multiple buffers, _writev style. The offset and length parameters in dgram.send are now optional. Refactored the dgram benchmarks, and seperated them from net. Added docs for the new signature. Reviewed-By: James M Snell <[email protected]> Reviewed-By: Saúl Ibarra Corretgé <[email protected]> Fixes: #4302 PR-URL: #4374
1 parent 4126441 commit 137f53c

12 files changed

+455
-117
lines changed

Makefile

+4-1
Original file line numberDiff line numberDiff line change
@@ -501,7 +501,10 @@ bench-events: all
501501
bench-util: all
502502
@$(NODE) benchmark/common.js util
503503

504-
bench-all: bench bench-misc bench-array bench-buffer bench-url bench-events
504+
bench-dgram: all
505+
@$(NODE) benchmark/common.js dgram
506+
507+
bench-all: bench bench-misc bench-array bench-buffer bench-url bench-events bench-dgram bench-util
505508

506509
bench: bench-net bench-http bench-fs bench-tls
507510

benchmark/dgram/array-vs-concat.js

+80
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
// test UDP send throughput with the multi buffer API against Buffer.concat
2+
'use strict';
3+
4+
const common = require('../common.js');
5+
const PORT = common.PORT;
6+
7+
// `num` is the number of send requests to queue up each time.
8+
// Keep it reasonably high (>10) otherwise you're benchmarking the speed of
9+
// event loop cycles more than anything else.
10+
var bench = common.createBenchmark(main, {
11+
len: [64, 256, 512, 1024],
12+
num: [100],
13+
chunks: [1, 2, 4, 8],
14+
type: ['concat', 'multi'],
15+
dur: [5]
16+
});
17+
18+
var dur;
19+
var len;
20+
var num;
21+
var type;
22+
var chunk;
23+
var chunks;
24+
var encoding;
25+
26+
function main(conf) {
27+
dur = +conf.dur;
28+
len = +conf.len;
29+
num = +conf.num;
30+
type = conf.type;
31+
chunks = +conf.chunks;
32+
33+
chunk = []
34+
for (var i = 0; i < chunks; i++) {
35+
chunk.push(new Buffer(Math.round(len / chunks)));
36+
}
37+
38+
server();
39+
}
40+
41+
var dgram = require('dgram');
42+
43+
function server() {
44+
var sent = 0;
45+
var received = 0;
46+
var socket = dgram.createSocket('udp4');
47+
48+
var onsend = type === 'concat' ? onsendConcat : onsendMulti;
49+
50+
function onsendConcat() {
51+
if (sent++ % num == 0)
52+
for (var i = 0; i < num; i++) {
53+
socket.send(Buffer.concat(chunk), PORT, '127.0.0.1', onsend);
54+
}
55+
}
56+
57+
function onsendMulti() {
58+
if (sent++ % num == 0)
59+
for (var i = 0; i < num; i++) {
60+
socket.send(chunk, PORT, '127.0.0.1', onsend);
61+
}
62+
}
63+
64+
socket.on('listening', function() {
65+
bench.start();
66+
onsend();
67+
68+
setTimeout(function() {
69+
var bytes = sent * len;
70+
var gbits = (bytes * 8) / (1024 * 1024 * 1024);
71+
bench.end(gbits);
72+
}, dur * 1000);
73+
});
74+
75+
socket.on('message', function(buf, rinfo) {
76+
received++;
77+
});
78+
79+
socket.bind(PORT);
80+
}

benchmark/dgram/multi-buffer.js

+70
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
// test UDP send/recv throughput with the multi buffer API
2+
'use strict';
3+
4+
const common = require('../common.js');
5+
const PORT = common.PORT;
6+
7+
// `num` is the number of send requests to queue up each time.
8+
// Keep it reasonably high (>10) otherwise you're benchmarking the speed of
9+
// event loop cycles more than anything else.
10+
var bench = common.createBenchmark(main, {
11+
len: [64, 256, 1024],
12+
num: [100],
13+
chunks: [1, 2, 4, 8],
14+
type: ['send', 'recv'],
15+
dur: [5]
16+
});
17+
18+
var dur;
19+
var len;
20+
var num;
21+
var type;
22+
var chunk;
23+
var chunks;
24+
var encoding;
25+
26+
function main(conf) {
27+
dur = +conf.dur;
28+
len = +conf.len;
29+
num = +conf.num;
30+
type = conf.type;
31+
chunks = +conf.chunks;
32+
33+
chunk = []
34+
for (var i = 0; i < chunks; i++) {
35+
chunk.push(new Buffer(Math.round(len / chunks)));
36+
}
37+
38+
server();
39+
}
40+
41+
var dgram = require('dgram');
42+
43+
function server() {
44+
var sent = 0;
45+
var received = 0;
46+
var socket = dgram.createSocket('udp4');
47+
48+
function onsend() {
49+
if (sent++ % num == 0)
50+
for (var i = 0; i < num; i++)
51+
socket.send(chunk, PORT, '127.0.0.1', onsend);
52+
}
53+
54+
socket.on('listening', function() {
55+
bench.start();
56+
onsend();
57+
58+
setTimeout(function() {
59+
var bytes = (type === 'send' ? sent : received) * len;
60+
var gbits = (bytes * 8) / (1024 * 1024 * 1024);
61+
bench.end(gbits);
62+
}, dur * 1000);
63+
});
64+
65+
socket.on('message', function(buf, rinfo) {
66+
received++;
67+
});
68+
69+
socket.bind(PORT);
70+
}

benchmark/net/dgram.js benchmark/dgram/offset-length.js

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
// test UDP send/recv throughput
1+
// test UDP send/recv throughput with the "old" offset/length API
2+
'use strict';
23

3-
var common = require('../common.js');
4-
var PORT = common.PORT;
4+
const common = require('../common.js');
5+
const PORT = common.PORT;
56

67
// `num` is the number of send requests to queue up each time.
78
// Keep it reasonably high (>10) otherwise you're benchmarking the speed of

benchmark/dgram/single-buffer.js

+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// test UDP send/recv throughput with the new single Buffer API
2+
'use strict';
3+
4+
const common = require('../common.js');
5+
const PORT = common.PORT;
6+
7+
// `num` is the number of send requests to queue up each time.
8+
// Keep it reasonably high (>10) otherwise you're benchmarking the speed of
9+
// event loop cycles more than anything else.
10+
var bench = common.createBenchmark(main, {
11+
len: [1, 64, 256, 1024],
12+
num: [100],
13+
type: ['send', 'recv'],
14+
dur: [5]
15+
});
16+
17+
var dur;
18+
var len;
19+
var num;
20+
var type;
21+
var chunk;
22+
var encoding;
23+
24+
function main(conf) {
25+
dur = +conf.dur;
26+
len = +conf.len;
27+
num = +conf.num;
28+
type = conf.type;
29+
chunk = new Buffer(len);
30+
server();
31+
}
32+
33+
var dgram = require('dgram');
34+
35+
function server() {
36+
var sent = 0;
37+
var received = 0;
38+
var socket = dgram.createSocket('udp4');
39+
40+
function onsend() {
41+
if (sent++ % num == 0)
42+
for (var i = 0; i < num; i++)
43+
socket.send(chunk, PORT, '127.0.0.1', onsend);
44+
}
45+
46+
socket.on('listening', function() {
47+
bench.start();
48+
onsend();
49+
50+
setTimeout(function() {
51+
var bytes = (type === 'send' ? sent : received) * chunk.length;
52+
var gbits = (bytes * 8) / (1024 * 1024 * 1024);
53+
bench.end(gbits);
54+
}, dur * 1000);
55+
});
56+
57+
socket.on('message', function(buf, rinfo) {
58+
received++;
59+
});
60+
61+
socket.bind(PORT);
62+
}

doc/api/dgram.markdown

+23-3
Original file line numberDiff line numberDiff line change
@@ -185,9 +185,10 @@ never have reason to call this.
185185
If `multicastInterface` is not specified, the operating system will attempt to
186186
drop membership on all valid interfaces.
187187

188-
### socket.send(buf, offset, length, port, address[, callback])
188+
### socket.send(buf, [offset, length,] port, address[, callback])
189189

190-
* `buf` Buffer object or string. Message to be sent
190+
* `buf` Buffer object, string, or an array of either. Message to be
191+
sent.
191192
* `offset` Integer. Offset in the buffer where the message starts.
192193
* `length` Integer. Number of bytes in the message.
193194
* `port` Integer. Destination port.
@@ -224,17 +225,36 @@ The only way to know for sure that the datagram has been sent is by using a
224225
passed as the first argument to the `callback`. If a `callback` is not given,
225226
the error is emitted as an `'error'` event on the `socket` object.
226227

228+
Offset and length are optional, but if you specify one you would need to
229+
specify the other. Also, they are supported only when the first
230+
argument is a `Buffer`.
231+
227232
Example of sending a UDP packet to a random port on `localhost`;
228233

229234
```js
230235
const dgram = require('dgram');
231236
const message = new Buffer('Some bytes');
232237
const client = dgram.createSocket('udp4');
233-
client.send(message, 0, message.length, 41234, 'localhost', (err) => {
238+
client.send(message, 41234, 'localhost', (err) => {
239+
client.close();
240+
});
241+
```
242+
243+
Example of sending a UDP packet composed of multiple buffers to a random port on `localhost`;
244+
245+
```js
246+
const dgram = require('dgram');
247+
const buf1 = new Buffer('Some ');
248+
const buf2 = new Buffer('bytes');
249+
const client = dgram.createSocket('udp4');
250+
client.send([buf1, buf2], 41234, 'localhost', (err) => {
234251
client.close();
235252
});
236253
```
237254

255+
Sending multiple buffers might be faster or slower depending on your
256+
application and operating system: benchmark it. Usually it is faster.
257+
238258
**A Note about UDP datagram size**
239259

240260
The maximum size of an `IPv4/v6` datagram depends on the `MTU`

0 commit comments

Comments
 (0)