Node.js v12.4.0 文档


dgram(数据报)#

查看v10.x中文文档

Stability: 2 - Stable

The dgram module provides an implementation of UDP Datagram sockets.

const dgram = require('dgram');
const server = dgram.createSocket('udp4');

server.on('error', (err) => {
  console.log(`server error:\n${err.stack}`);
  server.close();
});

server.on('message', (msg, rinfo) => {
  console.log(`server got: ${msg} from ${rinfo.address}:${rinfo.port}`);
});

server.on('listening', () => {
  const address = server.address();
  console.log(`server listening ${address.address}:${address.port}`);
});

server.bind(41234);
// Prints: server listening 0.0.0.0:41234

dgram.Socket 类#

中英对照提交修改

dgram.Socket对象是一个封装了数据包函数功能的EventEmitter

dgram.Socket实例是由dgram.createSocket()创建的。创建dgram.Socket实例不需要使用new关键字。

'close' 事件#

中英对照提交修改

'close'事件将在使用close()关闭一个 socket 之后触发。该事件一旦触发,这个 socket 上将不会触发新的'message'事件。

Event: 'connect'#

暂无中英对照

The 'connect' event is emitted after a socket is associated to a remote address as a result of a successful connect() call.

'error' 事件#

中英对照提交修改

当有任何错误发生时, 'error'事件将被触发。事件发生时,事件处理函数仅会接收到一个 Error 参数。

'listening' 事件#

中英对照提交修改

当一个 socket 开始监听数据包信息时, 'listening'事件将被触发。该事件会在创建 UDP socket 之后被立即触发。

'message' 事件#

中英对照提交修改

当有新的数据包被 socket 接收时, 'message'事件会被触发。msgrinfo会作为参数传递到该事件的处理函数中。

socket.addMembership(multicastAddress[, multicastInterface])#

中英对照提交修改

通知内核将multicastAddressmulticastInterface提供的多路传送集合通过IP_ADD_MEMBERSHIP这个 socket 选项结合起来。若multicastInterface参数未指定,操作系统将会选择一个接口并向其添加成员。要为所有可用的接口添加成员,可以在每个接口上调用一次addMembership方法。

socket.address()#

中英对照提交修改

返回一个包含 socket 地址信息的对象。对于 UDP socket,该对象将包含addressfamilyport属性。

socket.bind([port][, address][, callback])#

查看v10.x中文文档

For UDP sockets, causes the dgram.Socket to listen for datagram messages on a named port and optional address. If port is not specified or is 0, the operating system will attempt to bind to a random port. If address is not specified, the operating system will attempt to listen on all addresses. Once binding is complete, a 'listening' event is emitted and the optional callback function is called.

Note that specifying both a 'listening' event listener and passing a callback to the socket.bind() method is not harmful but not very useful.

A bound datagram socket keeps the Node.js process running to receive datagram messages.

If binding fails, an 'error' event is generated. In rare case (e.g. attempting to bind with a closed socket), an Error may be thrown.

Example of a UDP server listening on port 41234:

const dgram = require('dgram');
const server = dgram.createSocket('udp4');

server.on('error', (err) => {
  console.log(`server error:\n${err.stack}`);
  server.close();
});

server.on('message', (msg, rinfo) => {
  console.log(`server got: ${msg} from ${rinfo.address}:${rinfo.port}`);
});

server.on('listening', () => {
  const address = server.address();
  console.log(`server listening ${address.address}:${address.port}`);
});

server.bind(41234);
// Prints: server listening 0.0.0.0:41234

socket.bind(options[, callback])#

查看v10.x中文文档

For UDP sockets, causes the dgram.Socket to listen for datagram messages on a named port and optional address that are passed as properties of an options object passed as the first argument. If port is not specified or is 0, the operating system will attempt to bind to a random port. If address is not specified, the operating system will attempt to listen on all addresses. Once binding is complete, a 'listening' event is emitted and the optional callback function is called.

The options object may contain a fd property. When a fd greater than 0 is set, it will wrap around an existing socket with the given file descriptor. In this case, the properties of port and address will be ignored.

Note that specifying both a 'listening' event listener and passing a callback to the socket.bind() method is not harmful but not very useful.

The options object may contain an additional exclusive property that is used when using dgram.Socket objects with the cluster module. When exclusive is set to false (the default), cluster workers will use the same underlying socket handle allowing connection handling duties to be shared. When exclusive is true, however, the handle is not shared and attempted port sharing results in an error.

A bound datagram socket keeps the Node.js process running to receive datagram messages.

If binding fails, an 'error' event is generated. In rare case (e.g. attempting to bind with a closed socket), an Error may be thrown.

An example socket listening on an exclusive port is shown below.

socket.bind({
  address: 'localhost',
  port: 8000,
  exclusive: true
});

socket.close([callback])#

中英对照提交修改

关闭该 socket 并停止监听其上的数据。如果提供了一个回调函数,它就相当于为'close'事件添加了一个监听器。

socket.connect(port[, address][, callback])#

暂无中英对照

Associates the dgram.Socket to a remote address and port. Every message sent by this handle is automatically sent to that destination. Also, the socket will only receive messages from that remote peer. Trying to call connect() on an already connected socket will result in an ERR_SOCKET_DGRAM_IS_CONNECTED exception. If address is not provided, '127.0.0.1' (for udp4 sockets) or '::1' (for udp6 sockets) will be used by default. Once the connection is complete, a 'connect' event is emitted and the optional callback function is called. In case of failure, the callback is called or, failing this, an 'error' event is emitted.

socket.disconnect()#

暂无中英对照

A synchronous function that disassociates a connected dgram.Socket from its remote address. Trying to call disconnect() on an already disconnected socket will result in an ERR_SOCKET_DGRAM_NOT_CONNECTED exception.

socket.dropMembership(multicastAddress[, multicastInterface])#

中英对照提交修改

引导内核通过IP_DROP_MEMBERSHIP这个 socket 选项删除multicastAddress指定的多路传送集合。当 socket 被关闭或进程被终止时,该方法会被内核自动调用,所以大多数的应用都不用自行调用该方法。

multicastInterface未指定,操作系统会尝试删除所有可用接口上的成员。

socket.getRecvBufferSize()#

中英对照提交修改

  • Returns <number> socket 接收到的字节大小。

socket.getSendBufferSize()#

中英对照提交修改

  • Returns <number> socket 发送的字节大小。

socket.ref()#

中英对照提交修改

默认情况下,绑定一个 socket 会在 socket 运行时阻止 Node.js 进程退出。 socket.unref() 方法用于将 socket 从维持 Node.js 进程的引用列表中解除。 socket.ref() 方法用于将 socket 重新添加到这个引用列表中,并恢复其默认行为。

多次调用 socket.ref() 不会有额外的作用。

socket.ref() 方法返回一个对 socket 的引用,所以可以链式调用。

socket.remoteAddress()#

暂无中英对照

Returns an object containing the address, family, and port of the remote endpoint. It throws an ERR_SOCKET_DGRAM_NOT_CONNECTED exception if the socket is not connected.

socket.send(msg[, offset, length][, port][, address][, callback])#

查看v10.x中文文档

Broadcasts a datagram on the socket. For connectionless sockets, the destination port and address must be specified. Connected sockets, on the other hand, will use their associated remote endpoint, so the port and address arguments must not be set.

The msg argument contains the message to be sent. Depending on its type, different behavior can apply. If msg is a Buffer or Uint8Array, the offset and length specify the offset within the Buffer where the message begins and the number of bytes in the message, respectively. If msg is a String, then it is automatically converted to a Buffer with 'utf8' encoding. With messages that contain multi-byte characters, offset and length will be calculated with respect to byte length and not the character position. If msg is an array, offset and length must not be specified.

The address argument is a string. If the value of address is a host name, DNS will be used to resolve the address of the host. If address is not provided or otherwise falsy, '127.0.0.1' (for udp4 sockets) or '::1' (for udp6 sockets) will be used by default.

If the socket has not been previously bound with a call to bind, the socket is assigned a random port number and is bound to the "all interfaces" address ('0.0.0.0' for udp4 sockets, '::0' for udp6 sockets.)

An optional callback function may be specified to as a way of reporting DNS errors or for determining when it is safe to reuse the buf object. Note that DNS lookups delay the time to send for at least one tick of the Node.js event loop.

The only way to know for sure that the datagram has been sent is by using a callback. If an error occurs and a callback is given, the error will be passed as the first argument to the callback. If a callback is not given, the error is emitted as an 'error' event on the socket object.

Offset and length are optional but both must be set if either are used. They are supported only when the first argument is a Buffer or Uint8Array.

Example of sending a UDP packet to a port on localhost;

const dgram = require('dgram');
const message = Buffer.from('Some bytes');
const client = dgram.createSocket('udp4');
client.send(message, 41234, 'localhost', (err) => {
  client.close();
});

Example of sending a UDP packet composed of multiple buffers to a port on 127.0.0.1;

const dgram = require('dgram');
const buf1 = Buffer.from('Some ');
const buf2 = Buffer.from('bytes');
const client = dgram.createSocket('udp4');
client.send([buf1, buf2], 41234, (err) => {
  client.close();
});

Sending multiple buffers might be faster or slower depending on the application and operating system. It is important to run benchmarks to determine the optimal strategy on a case-by-case basis. Generally speaking, however, sending multiple buffers is faster.

Example of sending a UDP packet using a socket connected to a port on localhost:

const dgram = require('dgram');
const message = Buffer.from('Some bytes');
const client = dgram.createSocket('udp4');
client.connect(41234, 'localhost', (err) => {
  client.send(message, (err) => {
    client.close();
  });
});

A Note about UDP datagram size

The maximum size of an IPv4/v6 datagram depends on the MTU (Maximum Transmission Unit) and on the Payload Length field size.

  • The Payload Length field is 16 bits wide, which means that a normal payload exceed 64K octets including the internet header and data (65,507 bytes = 65,535 − 8 bytes UDP header − 20 bytes IP header); this is generally true for loopback interfaces, but such long datagram messages are impractical for most hosts and networks.

  • The MTU is the largest size a given link layer technology can support for datagram messages. For any link, IPv4 mandates a minimum MTU of 68 octets, while the recommended MTU for IPv4 is 576 (typically recommended as the MTU for dial-up type applications), whether they arrive whole or in fragments.

    For IPv6, the minimum MTU is 1280 octets, however, the mandatory minimum fragment reassembly buffer size is 1500 octets. The value of 68 octets is very small, since most current link layer technologies, like Ethernet, have a minimum MTU of 1500.

It is impossible to know in advance the MTU of each link through which a packet might travel. Sending a datagram greater than the receiver MTU will not work because the packet will get silently dropped without informing the source that the data did not reach its intended recipient.

socket.setBroadcast(flag)#

中英对照提交修改

设置或清除 SO_BROADCAST socket 选项。当设置为 true, UDP包可能会被发送到一个本地接口的广播地址

socket.setMulticastInterface(multicastInterface)#

暂无中英对照提交修改

All references to scope in this section are referring to IPv6 Zone Indices, which are defined by RFC 4007. In string form, an IP with a scope index is written as 'IP%scope' where scope is an interface name or interface number.

Sets the default outgoing multicast interface of the socket to a chosen interface or back to system interface selection. The multicastInterface must be a valid string representation of an IP from the socket's family.

For IPv4 sockets, this should be the IP configured for the desired physical interface. All packets sent to multicast on the socket will be sent on the interface determined by the most recent successful use of this call.

For IPv6 sockets, multicastInterface should include a scope to indicate the interface as in the examples that follow. In IPv6, individual send calls can also use explicit scope in addresses, so only packets sent to a multicast address without specifying an explicit scope are affected by the most recent successful use of this call.

IPv6 发送多播数据包#

暂无中英对照提交修改

On most systems, where scope format uses the interface name:

const socket = dgram.createSocket('udp6');

socket.bind(1234, () => {
  socket.setMulticastInterface('::%eth1');
});

On Windows, where scope format uses an interface number:

const socket = dgram.createSocket('udp6');

socket.bind(1234, () => {
  socket.setMulticastInterface('::%2');
});

IPv4 发送多播数据包#

暂无中英对照提交修改

All systems use an IP of the host on the desired physical interface:

const socket = dgram.createSocket('udp4');

socket.bind(1234, () => {
  socket.setMulticastInterface('10.0.0.2');
});

调用的结果#

暂无中英对照提交修改

A call on a socket that is not ready to send or no longer open may throw a Not running Error.

If multicastInterface can not be parsed into an IP then an EINVAL System Error is thrown.

On IPv4, if multicastInterface is a valid address but does not match any interface, or if the address does not match the family then a System Error such as EADDRNOTAVAIL or EPROTONOSUP is thrown.

On IPv6, most errors with specifying or omitting scope will result in the socket continuing to use (or returning to) the system's default interface selection.

A socket's address family's ANY address (IPv4 '0.0.0.0' or IPv6 '::') can be used to return control of the sockets default outgoing interface to the system for future multicast packets.

socket.setMulticastLoopback(flag)#

中英对照提交修改

设置或清除 IP_MULTICAST_LOOP socket 选项。当设置为 true, 多播数据包也将在本地接口接收。

socket.setMulticastTTL(ttl)#

中英对照提交修改

设置IP_MULTICAST_TTL套接字选项。 一般来说,TTL表示"生存时间"。这里特指一个IP数据包传输时允许的最大跳步数,尤其是对多播传输。 当IP数据包每向前经过一个路由或网关时,TTL值减1,若经过某个路由时,TTL值被减至0,便不再继续向前传输。

传给 socket.setMulticastTTL() 的参数是一个范围为0-255的跳步数。大多数系统的默认值是 1 ,但是可以变化。

socket.setRecvBufferSize(size)#

中英对照提交修改

设置 SO_RCVBUF 套接字选项。设置最大的套接字接收缓冲字节。

socket.setSendBufferSize(size)#

中英对照提交修改

设置 SO_SNDBUF 套接字选项。设置最大的套接字发送缓冲字节。

socket.setTTL(ttl)#

中英对照提交修改

设置 IP_TTL 套接字选项。 一般来说,TTL表示"生存时间",这里特指一个IP数据包传输时允许的最大跳步数。 当IP数据包每向前经过一个路由或网关时,TTL值减1,若经过某个路由时,TTL值被减至0,便不再继续向前传输。 比较有代表性的是,为了进行网络情况嗅探或者多播而修改TTL值。

传给 socket.setTTL() 的参数是一个范围为0-255的跳步数。大多数系统的默认值是 1 ,但是可以变化。

socket.unref()#

中英对照提交修改

默认情况下,只要socket是打开的,绑定一个socket将导致它阻塞Node.js进程退出。使用socket.unref()方法可以从保持Node.js进程活动的引用计数中排除socket,从而允许进程退出,尽管这个socket仍然在侦听。

多次调用socket.unref()方法将不会有任何新增的作用。

socket.unref()方法返回当前socket的引用,因此可以链式调用。

更改为异步的 socket.bind()#

中英对照提交修改

从Node.js v0.10开始,[dgram.Socket#bind()][]更改为异步执行模型。旧代码采用同步行为,如下例所示:

const s = dgram.createSocket('udp4');
s.bind(1234);
s.addMembership('224.0.0.114');

必须改为传递一个回调函数到[dgram.Socket#bind()][]:

const s = dgram.createSocket('udp4');
s.bind(1234, () => {
  s.addMembership('224.0.0.114');
});

dgram 模块的函数#

dgram.createSocket(options[, callback])#

查看v10.x中文文档

  • options <Object> Available options are:

    • type <string> The family of socket. Must be either 'udp4' or 'udp6'. Required.
    • reuseAddr <boolean> When true socket.bind() will reuse the address, even if another process has already bound a socket on it. Default: false.
    • ipv6Only <boolean> Setting ipv6Only to true will disable dual-stack support, i.e., binding to address :: won't make 0.0.0.0 be bound. Default: false.
    • recvBufferSize <number> - Sets the SO_RCVBUF socket value.
    • sendBufferSize <number> - Sets the SO_SNDBUF socket value.
    • lookup <Function> Custom lookup function. Default: dns.lookup().
  • callback <Function> Attached as a listener for 'message' events. Optional.
  • Returns: <dgram.Socket>

Creates a dgram.Socket object. Once the socket is created, calling socket.bind() will instruct the socket to begin listening for datagram messages. When address and port are not passed to socket.bind() the method will bind the socket to the "all interfaces" address on a random port (it does the right thing for both udp4 and udp6 sockets). The bound address and port can be retrieved using socket.address().address and socket.address().port.

dgram.createSocket(type[, callback])#

查看v10.x中文文档

Creates a dgram.Socket object of the specified type. The type argument can be either 'udp4' or 'udp6'. An optional callback function can be passed which is added as a listener for 'message' events.

Once the socket is created, calling socket.bind() will instruct the socket to begin listening for datagram messages. When address and port are not passed to socket.bind() the method will bind the socket to the "all interfaces" address on a random port (it does the right thing for both udp4 and udp6 sockets). The bound address and port can be retrieved using socket.address().address and socket.address().port.