Node.js dgram 模块详解
Node.js 的 dgram
模块提供了 UDP(User Datagram Protocol)数据报套接字的实现。UDP 是一种无连接的传输层协议,与 TCP 不同,它不保证数据的可靠传输,但具有更低的延迟和更高的传输效率。
主要特点
- 无连接:不需要建立连接即可发送数据
- 轻量级:协议头部开销小(仅 8 字节)
- 高效:没有连接建立和断开的开销
- 不可靠:不保证数据包的顺序和到达
核心 API 解析
1. 创建套接字
实例
const dgram = require('dgram');
// 创建 UDP 套接字
const socket = dgram.createSocket('udp4'); // IPv4
// 或
const socket = dgram.createSocket('udp6'); // IPv6
// 创建 UDP 套接字
const socket = dgram.createSocket('udp4'); // IPv4
// 或
const socket = dgram.createSocket('udp6'); // IPv6
参数说明
udp4
:使用 IPv4udp6
:使用 IPv6
2. 绑定端口
实例
socket.bind(41234, () => {
console.log('Socket is listening on port 41234');
});
console.log('Socket is listening on port 41234');
});
可选参数
port
:绑定的端口号(默认随机)address
:绑定的 IP 地址(默认所有可用接口)callback
:绑定成功后的回调函数
3. 发送消息
实例
const message = Buffer.from('Hello UDP!');
const port = 41234;
const host = '127.0.0.1';
socket.send(message, port, host, (err) => {
if (err) throw err;
console.log('Message sent');
});
const port = 41234;
const host = '127.0.0.1';
socket.send(message, port, host, (err) => {
if (err) throw err;
console.log('Message sent');
});
参数说明
msg
:要发送的消息(Buffer、String 或 Array)offset
:消息在 Buffer 中的偏移量length
:消息的字节数port
:目标端口address
:目标地址callback
:发送完成后的回调
4. 接收消息
实例
socket.on('message', (msg, rinfo) => {
console.log(`Received ${msg.length} bytes from ${rinfo.address}:${rinfo.port}`);
console.log(`Message content: ${msg.toString()}`);
});
console.log(`Received ${msg.length} bytes from ${rinfo.address}:${rinfo.port}`);
console.log(`Message content: ${msg.toString()}`);
});
回调参数
msg
:接收到的消息(Buffer)rinfo
:远程地址信息对象address
:发送方 IPport
:发送方端口family
:IP 协议族(IPv4/IPv6)size
:消息大小(字节)
5. 关闭套接字
实例
socket.close(() => {
console.log('Socket closed');
});
console.log('Socket closed');
});
注意事项
- 关闭后不能再发送或接收消息
- 可以监听
'close'
事件
事件处理
dgram
套接字是一个 EventEmitter,可以监听以下事件:
1. 'message' 事件
当接收到新数据报时触发
2. 'listening' 事件
当套接字开始监听时触发
3. 'close' 事件
当套接字关闭时触发
4. 'error' 事件
当发生错误时触发
实例
socket.on('error', (err) => {
console.error(`Socket error:\n${err.stack}`);
socket.close();
});
console.error(`Socket error:\n${err.stack}`);
socket.close();
});
实际应用场景
1. 实时游戏
利用 UDP 的低延迟特性传输游戏状态更新
2. 视频/音频流
容忍少量数据丢失但需要低延迟的场景
3. DNS 查询
DNS 协议通常使用 UDP
4. 网络发现协议
如 SSDP(简单服务发现协议)
完整示例
UDP 服务器
实例
const dgram = require('dgram');
const server = dgram.createSocket('udp4');
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);
const server = dgram.createSocket('udp4');
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);
UDP 客户端
实例
const dgram = require('dgram');
const client = dgram.createSocket('udp4');
const message = Buffer.from('Hello UDP Server');
client.send(message, 41234, 'localhost', (err) => {
if (err) throw err;
console.log('Message sent');
client.close();
});
const client = dgram.createSocket('udp4');
const message = Buffer.from('Hello UDP Server');
client.send(message, 41234, 'localhost', (err) => {
if (err) throw err;
console.log('Message sent');
client.close();
});
注意事项
- 消息大小限制:UDP 数据报最大为 65507 字节(IPv4)
- 可靠性:需要应用层实现重传和确认机制
- 安全性:UDP 容易受到 IP 欺骗和 DDoS 攻击
- 防火墙:确保防火墙允许 UDP 流量
性能优化建议
- 重用套接字地址(SO_REUSEADDR)
- 适当调整接收缓冲区大小
- 批量处理消息减少系统调用
- 考虑使用 setRecvBufferSize() 和 setSendBufferSize()
总结
Node.js 的 dgram
模块为开发者提供了强大的 UDP 网络编程能力,特别适合需要低延迟、高效率的网络应用场景。虽然 UDP 不提供可靠性保证,但在许多实时应用中,这种权衡是可接受的。理解 UDP 的特性和 dgram
模块的 API 可以帮助开发者构建更高效的网络应用。
点我分享笔记