Skip to content

Commit 9e96017

Browse files
santigimenodanbev
authored andcommitted
dgram: add support for UDP connected sockets
Added the `dgram.connect()` and `dgram.disconnect()` methods that associate/disassociate a udp socket to/from a remote address. It optimizes for cases where lots of packets are sent to the same address. Also added the `dgram.remoteAddress()` method to retrieve the associated remote address. PR-URL: #26871 Reviewed-By: Colin Ihrig <[email protected]> Reviewed-By: Matteo Collina <[email protected]>
1 parent 38f0e38 commit 9e96017

18 files changed

+736
-63
lines changed

doc/api/dgram.md

+72-3
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,14 @@ added: v0.1.99
4949
The `'close'` event is emitted after a socket is closed with [`close()`][].
5050
Once triggered, no new `'message'` events will be emitted on this socket.
5151

52+
### Event: 'connect'
53+
<!-- YAML
54+
added: REPLACEME
55+
-->
56+
57+
The `'connect'` event is emitted after a socket is associated to a remote
58+
address as a result of a successful [`connect()`][] call.
59+
5260
### Event: 'error'
5361
<!-- YAML
5462
added: v0.1.99
@@ -237,6 +245,34 @@ added: v0.1.99
237245
Close the underlying socket and stop listening for data on it. If a callback is
238246
provided, it is added as a listener for the [`'close'`][] event.
239247

248+
### socket.connect(port[, address][, callback])
249+
<!-- YAML
250+
added: REPLACEME
251+
-->
252+
253+
* `port` {integer}
254+
* `address` {string}
255+
* `callback` {Function} Called when the connection is completed or on error.
256+
257+
Associates the `dgram.Socket` to a remote address and port. Every
258+
message sent by this handle is automatically sent to that destination. Also,
259+
the socket will only receive messages from that remote peer.
260+
Trying to call `connect()` on an already connected socket will result
261+
in an [`ERR_SOCKET_DGRAM_IS_CONNECTED`][] exception. If `address` is not
262+
provided, `'127.0.0.1'` (for `udp4` sockets) or `'::1'` (for `udp6` sockets)
263+
will be used by default. Once the connection is complete, a `'connect'` event
264+
is emitted and the optional `callback` function is called. In case of failure,
265+
the `callback` is called or, failing this, an `'error'` event is emitted.
266+
267+
### socket.disconnect()
268+
<!-- YAML
269+
added: REPLACEME
270+
-->
271+
272+
A synchronous function that disassociates a connected `dgram.Socket` from
273+
its remote address. Trying to call `disconnect()` on an already disconnected
274+
socket will result in an [`ERR_SOCKET_DGRAM_NOT_CONNECTED`][] exception.
275+
240276
### socket.dropMembership(multicastAddress[, multicastInterface])
241277
<!-- YAML
242278
added: v0.6.9
@@ -283,7 +319,18 @@ Calling `socket.ref()` multiples times will have no additional effect.
283319
The `socket.ref()` method returns a reference to the socket so calls can be
284320
chained.
285321

286-
### socket.send(msg[, offset, length], port[, address][, callback])
322+
### socket.remoteAddress()
323+
<!-- YAML
324+
added: REPLACEME
325+
-->
326+
327+
* Returns: {Object}
328+
329+
Returns an object containing the `address`, `family`, and `port` of the remote
330+
endpoint. It throws an [`ERR_SOCKET_DGRAM_NOT_CONNECTED`][] exception if the
331+
socket is not connected.
332+
333+
### socket.send(msg[, offset, length][, port][, address][, callback])
287334
<!-- YAML
288335
added: v0.1.99
289336
changes:
@@ -301,6 +348,9 @@ changes:
301348
pr-url: https://github.com/nodejs/node/pull/4374
302349
description: The `msg` parameter can be an array now. Also, the `offset`
303350
and `length` parameters are optional now.
351+
- version: REPLACEME
352+
pr-url: https://github.com/nodejs/node/pull/26871
353+
description: Added support for sending data on connected sockets.
304354
-->
305355

306356
* `msg` {Buffer|Uint8Array|string|Array} Message to be sent.
@@ -310,8 +360,10 @@ changes:
310360
* `address` {string} Destination hostname or IP address.
311361
* `callback` {Function} Called when the message has been sent.
312362

313-
Broadcasts a datagram on the socket. The destination `port` and `address` must
314-
be specified.
363+
Broadcasts a datagram on the socket.
364+
For connectionless sockets, the destination `port` and `address` must be
365+
specified. Connected sockets, on the other hand, will use their associated
366+
remote endpoint, so the `port` and `address` arguments must not be set.
315367

316368
The `msg` argument contains the message to be sent.
317369
Depending on its type, different behavior can apply. If `msg` is a `Buffer`
@@ -375,6 +427,20 @@ application and operating system. It is important to run benchmarks to
375427
determine the optimal strategy on a case-by-case basis. Generally speaking,
376428
however, sending multiple buffers is faster.
377429

430+
Example of sending a UDP packet using a socket connected to a port on
431+
`localhost`:
432+
433+
```js
434+
const dgram = require('dgram');
435+
const message = Buffer.from('Some bytes');
436+
const client = dgram.createSocket('udp4');
437+
client.connect(41234, 'localhost', (err) => {
438+
client.send(message, (err) => {
439+
client.close();
440+
});
441+
});
442+
```
443+
378444
**A Note about UDP datagram size**
379445

380446
The maximum size of an `IPv4/v6` datagram depends on the `MTU`
@@ -651,10 +717,13 @@ and `udp6` sockets). The bound address and port can be retrieved using
651717

652718
[`'close'`]: #dgram_event_close
653719
[`Error`]: errors.html#errors_class_error
720+
[`ERR_SOCKET_DGRAM_IS_CONNECTED`]: errors.html#errors_err_socket_dgram_is_connected
721+
[`ERR_SOCKET_DGRAM_NOT_CONNECTED`]: errors.html#errors_err_socket_dgram_not_connected
654722
[`EventEmitter`]: events.html
655723
[`System Error`]: errors.html#errors_class_systemerror
656724
[`close()`]: #dgram_socket_close_callback
657725
[`cluster`]: cluster.html
726+
[`connect()`]: #dgram_socket_connect_port_address_callback
658727
[`dgram.Socket#bind()`]: #dgram_socket_bind_options_callback
659728
[`dgram.createSocket()`]: #dgram_dgram_createsocket_options_callback
660729
[`dns.lookup()`]: dns.html#dns_dns_lookup_hostname_options_callback

doc/api/errors.md

+14
Original file line numberDiff line numberDiff line change
@@ -1645,6 +1645,17 @@ Data could be sent on a socket.
16451645

16461646
An attempt was made to operate on an already closed socket.
16471647

1648+
<a id="ERR_SOCKET_DGRAM_IS_CONNECTED"></a>
1649+
### ERR_SOCKET_DGRAM_IS_CONNECTED
1650+
1651+
A [`dgram.connect()`][] call was made on an already connected socket.
1652+
1653+
<a id="ERR_SOCKET_DGRAM_NOT_CONNECTED"></a>
1654+
### ERR_SOCKET_DGRAM_NOT_CONNECTED
1655+
1656+
A [`dgram.disconnect()`][] or [`dgram.remoteAddress()`][] call was made on a
1657+
disconnected socket.
1658+
16481659
<a id="ERR_SOCKET_DGRAM_NOT_RUNNING"></a>
16491660
### ERR_SOCKET_DGRAM_NOT_RUNNING
16501661

@@ -2288,7 +2299,10 @@ such as `process.stdout.on('data')`.
22882299
[`crypto.scrypt()`]: crypto.html#crypto_crypto_scrypt_password_salt_keylen_options_callback
22892300
[`crypto.scryptSync()`]: crypto.html#crypto_crypto_scryptsync_password_salt_keylen_options
22902301
[`crypto.timingSafeEqual()`]: crypto.html#crypto_crypto_timingsafeequal_a_b
2302+
[`dgram.connect()`]: dgram.html#dgram_socket_connect_port_address_callback
22912303
[`dgram.createSocket()`]: dgram.html#dgram_dgram_createsocket_options_callback
2304+
[`dgram.disconnect()`]: dgram.html#dgram_socket_disconnect
2305+
[`dgram.remoteAddress()`]: dgram.html#dgram_socket_remoteaddress
22922306
[`errno`(3) man page]: http://man7.org/linux/man-pages/man3/errno.3.html
22932307
[`fs.readFileSync`]: fs.html#fs_fs_readfilesync_path_options
22942308
[`fs.readdir`]: fs.html#fs_fs_readdir_path_options_callback

0 commit comments

Comments
 (0)