- assert - 断言
- async_hooks - 异步钩子
- Buffer - 缓冲器
- child_process - 子进程
- cluster - 集群
- console - 控制台
- crypto - 加密
- debugger - 调试器
- dgram - 数据报
- dns - 域名服务器
- domain - 域
- Error - 错误
- events - 事件触发器
- fs - 文件系统
- global - 全局变量
- http - HTTP
- http2 - HTTP/2
- https - HTTPS
- inspector - 检查器
- module - 模块
- net - 网络
- os - 操作系统
- path - 路径
- perf_hooks - 性能钩子
- process - 进程
- punycode - 域名代码
- querystring - 查询字符串
- readline - 逐行读取
- repl - 交互式解释器
- stream - 流
- string_decoder - 字符串解码器
- timer - 定时器
- tls - 安全传输层
- trace_events - 跟踪事件
- tty - 终端
- url - URL
- util - 实用工具
- v8 - V8引擎
- vm - 虚拟机
- wasi - WASI
- worker_threads - 工作线程
- zlib - 压缩
目录
- dgram(数据报)
- dgram.Socket 类
- 'close' 事件
- 'connect' 事件
- 'error' 事件
- 'listening' 事件
- 'message' 事件
socket.addMembership(multicastAddress[, multicastInterface])
socket.addSourceSpecificMembership(sourceAddress, groupAddress[, multicastInterface])
socket.address()
socket.bind([port][, address][, callback])
socket.bind(options[, callback])
socket.close([callback])
socket.connect(port[, address][, callback])
socket.disconnect()
socket.dropMembership(multicastAddress[, multicastInterface])
socket.dropSourceSpecificMembership(sourceAddress, groupAddress[, multicastInterface])
socket.getRecvBufferSize()
socket.getSendBufferSize()
socket.ref()
socket.remoteAddress()
socket.send(msg[, offset, length][, port][, address][, callback])
socket.setBroadcast(flag)
socket.setMulticastInterface(multicastInterface)
socket.setMulticastLoopback(flag)
socket.setMulticastTTL(ttl)
socket.setRecvBufferSize(size)
socket.setSendBufferSize(size)
socket.setTTL(ttl)
socket.unref()
- dgram 模块的函数
- dgram.Socket 类
dgram(数据报)#
源代码: lib/dgram.js
dgram
模块提供了 UDP 数据包 socket 的实现。
const dgram = require('dgram');
const server = dgram.createSocket('udp4');
server.on('error', (err) => {
console.log(`服务器异常:\n${err.stack}`);
server.close();
});
server.on('message', (msg, rinfo) => {
console.log(`服务器接收到来自 ${rinfo.address}:${rinfo.port} 的 ${msg}`);
});
server.on('listening', () => {
const address = server.address();
console.log(`服务器监听 ${address.address}:${address.port}`);
});
server.bind(41234);
// 服务器监听 0.0.0.0:41234
dgram.Socket 类#
- 继承自: <EventEmitter>
封装了数据报的功能。
使用 dgram.createSocket()
创建 dgram.Socket
的新实例。
不能使用 new
关键字创建 dgram.Socket
实例。
'close' 事件#
'close'
事件将在使用 close()
关闭一个 socket 之后触发。
该事件一旦触发,则这个 socket 上将不会触发新的 'message'
事件。
'connect' 事件#
因 connect()
调用成功而使 socket 与远程地址关联之后,则会触发 'connect'
事件。
'error' 事件#
exception
<Error>
当有任何错误发生时, 'error'
事件将被触发。
事件发生时,事件处理函数仅会接收到一个 Error
对象。
'listening' 事件#
每当 dgram.Socket
可被寻址且可以接收数据时,就会触发 'listening'
事件。
这会发生在,显式地使用 socket.bind()
、或者隐式地使用 socket.send()
第一次发送数据。
在 dgram.Socket
开始监听之前,底层的系统资源并不存在,且诸如 socket.address()
和 socket.setTTL()
之类的调用都会失败。
'message' 事件#
当有新的数据包被 socket 接收时, 'message'
事件会被触发。msg
和 rinfo
会作为参数传递到该事件的处理函数中。
If the source address of the incoming packet is an IPv6 link-local
address, the interface name is added to the address
. For
example, a packet received on the en0
interface might have the
address field set to 'fe80::2618:1234:ab11:3b9c%en0'
, where '%en0'
is the interface name as a zone ID suffix.
socket.addMembership(multicastAddress[, multicastInterface])
#
通知内核将 multicastAddress
和 multicastInterface
提供的多路传送集合通过 IP_ADD_MEMBERSHIP
这个 socket 选项结合起来。
若 multicastInterface
参数未指定,则操作系统将会选择一个接口并向其添加成员。
要为所有可用的接口添加成员,可以在每个接口上调用一次 addMembership
方法。
When called on an unbound socket, this method will implicitly bind to a random port, listening on all interfaces.
当多个 cluster
工作进程之间共享 UDP socket 时,则 socket.addMembership()
函数必须只能被调用一次,否则将会发生 EADDRINUSE
错误:
const cluster = require('cluster');
const dgram = require('dgram');
if (cluster.isMaster) {
cluster.fork(); // 可工作。
cluster.fork(); // 失败并抛出 EADDRINUSE。
} else {
const s = dgram.createSocket('udp4');
s.bind(1234, () => {
s.addMembership('224.0.0.114');
});
}
socket.addSourceSpecificMembership(sourceAddress, groupAddress[, multicastInterface])
#
Tells the kernel to join a source-specific multicast channel at the given
sourceAddress
and groupAddress
, using the multicastInterface
with the
IP_ADD_SOURCE_MEMBERSHIP
socket option. If the multicastInterface
argument
is not specified, the operating system will choose one interface and will add
membership to it. To add membership to every available interface, call
socket.addSourceSpecificMembership()
multiple times, once per interface.
When called on an unbound socket, this method will implicitly bind to a random port, listening on all interfaces.
socket.address()
#
- 返回: <Object>
返回一个包含 socket 地址信息的对象。
对于 UDP socket,该对象将包含 address
、 family
和 port
属性。
This method throws EBADF
if called on an unbound socket.
socket.bind([port][, address][, callback])
#
port
<integer>address
<string>callback
<Function> 没有参数。当绑定完成时会被调用。
对于 UDP socket,该方法会令 dgram.Socket
在指定的 port
和可选的 address
上监听数据包信息。
若 port
未指定或为 0
,操作系统会尝试绑定一个随机的端口。
若 address
未指定,操作系统会尝试在所有地址上监听。
绑定完成时会触发一个 'listening'
事件,并会调用 callback
方法。
同时监听 'listening'
事件和在 socket.bind()
方法中传入 callback
参数并不会带来坏处,但也不是很有用。
一个被绑定的数据包 socket 会令 Node.js 进程保持运行以接收数据包信息。
若绑定失败,一个 'error'
事件会被触发。
在极少数的情况下(例如尝试绑定一个已关闭的 socket),一个 Error
会被抛出。
一个监听 41234 端口的 UDP 服务器的例子:
const dgram = require('dgram');
const server = dgram.createSocket('udp4');
server.on('error', (err) => {
console.log(`服务器异常:\n${err.stack}`);
server.close();
});
server.on('message', (msg, rinfo) => {
console.log(`服务器收到:${msg} 来自 ${rinfo.address}:${rinfo.port}`);
});
server.on('listening', () => {
const address = server.address();
console.log(`服务器监听 ${address.address}:${address.port}`);
});
server.bind(41234);
// 打印:服务器监听 0.0.0.0:41234
socket.bind(options[, callback])
#
options
<Object> 必要的。包含以下属性:callback
<Function>
对于 UDP socket,该方法会令 dgram.Socket
在指定的 port
和可选的 address
上监听数据包信息。
若 port
未指定或为 0
,操作系统会尝试绑定一个随机的端口。
若 address
未指定,操作系统会尝试在所有地址上监听。
绑定完成时会触发一个 'listening'
事件,并会调用 callback
方法。
options
对象可能包含 fd
属性。
当设置大于 0
的 fd
时,它将会使用给定的文件描述符封装一个现有的 socket。
在这种情况下, port
和 address
的属性将会忽略。
同时监听 'listening'
事件和在 socket.bind()
方法中传入 callback
参数并不会带来坏处,但也不是很有用。
在配合 cluster
模块使用 dgram.Socket
对象时, options
对象可能包含一个附加的 exclusive
属性。
当 exclusive
被设为 false
(默认值)时,集群工作进程会使用相同的 socket 句柄来共享连接处理作业。
当 exclusive
被设为 true
时,该句柄将不会被共享,而尝试共享端口则会造成错误。
一个绑定的数据报 socket 会使 Node.js 进程持续运行以接受数据报消息。
如果绑定失败,一个 'error'
事件会产生。在极少数情况下(例如尝试绑定一个已经关闭的 socket),一个 Error
可能抛出。
一个不共享端口的 socket 的例子如下文所示。
socket.bind({
address: 'localhost',
port: 8000,
exclusive: true
});
socket.close([callback])
#
callback
<Function> 当 socket 已被关闭时调用。
关闭该 socket 并停止监听其上的数据。
如果提供了一个回调函数,它就相当于为 'close'
事件添加了一个监听器。
socket.connect(port[, address][, callback])
#
port
<integer>address
<string>callback
<Function> 当连接完成或出错时调用。
为 dgram.Socket
关联一个远程地址和端口。
这个 socket 句柄发送的任何消息都会被发送到关联的远程地址。
而且,这个套接字会只接受来自那个远程同类的消息。
会导致一个 ERR_SOCKET_DGRAM_IS_CONNECTED
异常。
如果没有提供 address
,会默认用 '127.0.0.1'
(适用于 udp4
套接字)或者 '::1'
(适用于 udp6
套接字)。
一旦连接完成,一个 'connect'
会触发,并且可选的 callback
也会被调用。
为了防止失败,这个 callback
被调用或者调用失败触发一个 'error'
事件。
socket.disconnect()
#
一个将相连的 dgram.Socket
与远程地址断掉的同步函数。
在一个未绑定或已经断开连接的 socket 上尝试调用 disconnect()
会导致一个 ERR_SOCKET_DGRAM_NOT_CONNECTED
异常。
socket.dropMembership(multicastAddress[, multicastInterface])
#
引导内核通过 IP_DROP_MEMBERSHIP
这个 socket 选项删除 multicastAddress
指定的多路传送集合。
当 socket 被关闭或进程被终止时,该方法会被内核自动调用,所以大多数的应用都不用自行调用该方法。
若 multicastInterface
未指定,操作系统会尝试删除所有可用接口上的成员。
socket.dropSourceSpecificMembership(sourceAddress, groupAddress[, multicastInterface])
#
Instructs the kernel to leave a source-specific multicast channel at the given
sourceAddress
and groupAddress
using the IP_DROP_SOURCE_MEMBERSHIP
socket option. This method is automatically called by the kernel when the
socket is closed or the process terminates, so most apps will never have
reason to call this.
If multicastInterface
is not specified, the operating system will attempt to
drop membership on all valid interfaces.
socket.getRecvBufferSize()
#
- 返回 <number>
SO_RCVBUF
socket 接收到的 buffer 的大小,以字节为单位。
This method throws ERR_SOCKET_BUFFER_SIZE
if called on an unbound socket.
socket.getSendBufferSize()
#
- 返回 <number>
SO_SNDBUF
socket 发送的 buffer 的大小,以字节为单位。
This method throws ERR_SOCKET_BUFFER_SIZE
if called on an unbound socket.
socket.ref()
#
- 返回: <dgram.Socket>
默认情况下,绑定一个 socket 会在 socket 运行时阻止 Node.js 进程退出。
socket.unref()
方法用于将 socket 从维持 Node.js 进程的引用列表中解除。
socket.ref()
方法用于将 socket 重新添加到这个引用列表中,并恢复其默认行为。
多次调用 socket.ref()
不会有额外的作用。
socket.ref()
方法返回一个对 socket 的引用,所以可以链式调用。
socket.remoteAddress()
#
- Returns: <Object>
Returns an object containing the address
, family
, and port
of the remote
endpoint. This method throws an ERR_SOCKET_DGRAM_NOT_CONNECTED
exception
if the socket is not connected.
socket.send(msg[, offset, length][, port][, address][, callback])
#
msg
<Buffer> | <TypedArray> | <DataView> | <string> | <Array> 要发送的消息。offset
<integer> 指定消息的开头在 buffer 中的偏移量。length
<integer> 消息的字节数。port
<integer> 目标端口。address
<string> 目标主机名或 IP 地址。callback
<Function> 当消息被发送时会被调用。
在 socket 上广播一个数据包。
对于无连接的 socket,必须指定目标的 port
和 address
。
对于连接的 socket,则将会使用其关联的远程端点,因此不能设置 port
和 address
参数。
msg
参数包含了要发送的消息。
根据消息的类型可以有不同的做法。
如果 msg
是一个 Buffer
、 TypedArray
或 DataView
,则 offset
和 length
指定了消息在 Buffer
中对应的偏移量和字节数。
如果 msg
是一个 String
,那么它会被自动地按照 'utf8'
编码转换为 Buffer
。
对于包含了多字节字符的消息, offset
和 length
会根据对应的字节长度进行计算,而不是根据字符的位置。
如果 msg
是一个数组,那么 offset
和 length
必须都不能被指定。
address
参数是一个字符串。
若 address
的值是一个主机名,则 DNS 会被用来解析主机的地址。
若 address
未提供或是非真值,则 '127.0.0.1'
(用于 udp4
socket)或 '::1'
(用于 udp6
socket)会被使用。
若在之前 socket 未通过调用 bind
方法进行绑定,socket 将会被一个随机的端口号赋值并绑定到“所有接口”的地址上(对于 udp4
socket 是 '0.0.0.0'
,对于 udp6
socket 是 '::0'
)。
可以指定一个可选的 callback
方法来汇报 DNS 错误或判断可以安全地重用 buf
对象的时机。
在 Node.js 事件循环中,DNS 查询会对发送造成至少一个时间点的延迟。
确定数据包被发送的唯一方式就是指定 callback
。
若在 callback
被指定的情况下有错误发生,该错误会作为 callback
的第一个参数。
若 callback
未被指定,该错误会以 'error'
事件的方式投射到 socket
对象上。
偏移量和长度是可选的,但如其中一个被指定则另一个也必须被指定。
另外,它们只在第一个参数是 Buffer
、 TypedArray
或 DataView
的情况下才能被使用。
This method throws ERR_SOCKET_BAD_PORT
if called on an unbound socket.
示例,发送 UDP 包到 localhost
上的某个端口:
const dgram = require('dgram');
const message = Buffer.from('一些字节');
const client = dgram.createSocket('udp4');
client.send(message, 41234, 'localhost', (err) => {
client.close();
});
示例,发送包含多个 buffer 的 UDP 包到 127.0.0.1
上的某个端口:
const dgram = require('dgram');
const buf1 = Buffer.from('一些 ');
const buf2 = Buffer.from('字节');
const client = dgram.createSocket('udp4');
client.send([buf1, buf2], 41234, (err) => {
client.close();
});
发送多个 buffer 的速度取决于应用和操作系统。 逐案运行基准来确定最佳策略。 但是一般来说,发送多个 buffer 速度更快。
示例,使用已连接的 socket 发送 UDP 包到 localhost
上的某个端口:
const dgram = require('dgram');
const message = Buffer.from('一些字节');
const client = dgram.createSocket('udp4');
client.connect(41234, 'localhost', (err) => {
client.send(message, (err) => {
client.close();
});
});
关于 UDP 数据报大小的说明#
IPv4/v6 数据包的最大尺寸取决于 MTU
(Maximum Transmission Unit,最大传输单元)与 Payload Length
字段大小。
-
Payload Length
字段有 16 位宽,这意味着不能超过 64K 的包含 IP 头部和数据的负载 (65,507 字节 = 65,535 − 8 字节 UDP 头 − 20 字节 IP 头)。 通常对于环回地址来说是这样,但这个长度的数据包对于大多数的主机和网络来说不切实际。 -
MTU
指的是数据链路层为数据包提供的最大大小。 对于任意链路,IPv4 所托管的MTU
最小为 68 个字节,推荐为 576(典型地,作为拨号上网应用的推荐值),无论它们是完整地还是分块地抵达。对于 IPv6,
MTU
的最小值是 1280 个字节。但是,受托管的最小的碎片重组缓冲大小为 1500 个字节。 现今大多数的数据链路层技术(如以太网),都有 1500 的MTU
最小值,因而 68 个字节显得非常小。
要提前知道数据包可能经过的每个链路的 MTU 是不可能的。
发送大于接受者 MTU
大小的数据包将不会起作用,因为数据包会被静默地丢失,而不会通知发送者该包未抵达目的地。
socket.setBroadcast(flag)
#
flag
<boolean>
设置或清除 SO_BROADCAST
socket 选项。
当设置为 true
, UDP 包可能会被发送到一个本地接口的广播地址。
This method throws EBADF
if called on an unbound socket.
socket.setMulticastInterface(multicastInterface)
#
multicastInterface
<string>
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.
This method throws EBADF
if called on an unbound socket.
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)
#
flag
<boolean>
设置或清除 IP_MULTICAST_LOOP
socket 选项。当设置为 true
, 多播数据包也将在本地接口接收。
This method throws EBADF
if called on an unbound socket.
socket.setMulticastTTL(ttl)
#
ttl
<integer>
设置 IP_MULTICAST_TTL
套接字选项。
一般来说,TTL 表示"生存时间"。
这里特指一个 IP 数据包传输时允许的最大跳步数,尤其是对多播传输。
当 IP 数据包每向前经过一个路由或网关时,TTL 值减 1,若经过某个路由时,TTL 值被减至 0,便不再继续向前传输。
ttl
参数可以是 0
到 255
之间。
在大多数系统上,默认值是 1
。
This method throws EBADF
if called on an unbound socket.
socket.setRecvBufferSize(size)
#
size
<integer>
设置 SO_RCVBUF
socket 选项。
设置 socket 接收 buffer 的最大值,以字节为单位。
This method throws ERR_SOCKET_BUFFER_SIZE
if called on an unbound socket.
socket.setSendBufferSize(size)
#
size
<integer>
设置 SO_SNDBUF
socket 选项。
设置 socket 发送 buffer 的最大值,以字节为单位。
This method throws ERR_SOCKET_BUFFER_SIZE
if called on an unbound socket.
socket.setTTL(ttl)
#
ttl
<integer>
设置 IP_TTL
套接字选项。
一般来说,TTL 表示"生存时间",这里特指一个 IP 数据包传输时允许的最大跳步数。
当 IP 数据包每向前经过一个路由或网关时,TTL 值减 1,若经过某个路由时,TTL 值被减至 0,便不再继续向前传输。
比较有代表性的是,为了进行网络情况嗅探或者多播而修改 TTL 值。
ttl
参数可以是 0
到 255
之间。
在大多数系统上,默认值是 64
。
This method throws EBADF
if called on an unbound socket.
socket.unref()
#
- 返回: <dgram.Socket>
默认情况下,只要 socket 是打开的,绑定一个 socket 将导致它阻塞 Node.js 进程退出。
使用 socket.unref()
方法可以从保持 Node.js 进程活动的引用计数中排除 socket,从而允许进程退出,尽管这个 socket 仍然在侦听。
多次调用 socket.unref()
方法将不会有任何新增的作用。
socket.unref()
方法返回当前 socket 的引用,因此可以链式调用。
dgram 模块的函数#
dgram.createSocket(options[, callback])
#
options
<Object> 允许的选项是:type
<string> 套接字族. 必须是'udp4'
或'udp6'
。必需填。reuseAddr
<boolean> 若设置为true
,则socket.bind()
会重用地址,即使另一个进程已经在其上面绑定了一个套接字。默认值:false
。ipv6Only
<boolean> 将ipv6Only
设置为true
将会禁用双栈支持,即绑定到地址::
不会使0.0.0.0
绑定。默认值:false
。recvBufferSize
<number> 设置SO_RCVBUF
套接字值。sendBufferSize
<number> 设置SO_SNDBUF
套接字值。lookup
<Function> 自定义的查询函数。默认值:dns.lookup()
。
callback
<Function> 为'message'
事件绑定一个监听器。可选。- 返回: <dgram.Socket>
创建一个 dgram.Socket
对象。
一旦创建了套接字,调用 socket.bind()
会指示套接字开始监听数据报消息。
如果 address
和 port
没传给 socket.bind()
,那么这个方法会把这个套接字绑定到 "全部接口" 地址的一个随机端口(这适用于 udp4
和 udp6
套接字)。
绑定的地址和端口可以通过 socket.address().address
和socket.address().port
来获取。
dgram.createSocket(type[, callback])
#
type
<string>'udp4'
或'udp6'
。callback
<Function> 为'message'
事件添加一个监听器。- 返回: <dgram.Socket>
创建一个特定 type
的 dgram.Socket
对象。
一旦套接字被创建,调用 socket.bind()
会指示套接字开始监听数据报消息。
如果 address
和 port
没传给 socket.bind()
,那么这个方法会把这个套接字绑定到 "全部接口" 地址的一个随机端口(这适用于 udp4
和 udp6
套接字)。
绑定的地址和端口可以通过 socket.address().address
和socket.address().port
来获取。