Skip to main content

Node UDP 如何使用?

背景

最近新项目成功上线了,下一步就是联机组队。联机组队首先想到 Socket.IO,但它是基于 TCP 协议,理论上不太适合帧同步。于是决定使用 UDP。

TCP与UDP基本区别

  1. 基于连接与无连接
  2. TCP 要求系统资源较多,UDP 较少;
  3. UDP 程序结构较简单
  4. 流模式(TCP)与数据报模式(UDP);
  5. TCP 保证数据正确性,UDP 可能丢包
  6. TCP 保证数据顺序,UDP 不保证

UDP应用场景:

  1. 面向数据报方式
  2. 网络数据大多为短消息
  3. 拥有大量 Client
  4. 数据安全性无特殊要求
  5. 网络负担非常重,但对响应速度要求高

Dome

既然用 Node,我们要采取一个关键的内置 模块 dgram 模块,它用于创建基于 UDP(User Datagram Protocol)的数据报(datagram)套接字。UDP 是一种无连接的传输层协议,常用于需要快速、低延迟传输的应用场景。

按照惯例我们先写一个配置文件 config.json

{	 	
"serverHost": "127.0.0.1",
"port": 6666,
"timeout": 8888,
}

实现服务端的 UDP udpServer.js

const udp = require('dgram');
const conf = require('./config.json');

// 创建 UPD 服务
const server = udp.createSocket('udp4');

// 发生错误时的操作
server.on('error', error => {
console.log('UDP 服务错误', error);
server.close();
});

// 接收信息,回应
server.on('message', (msg, info) => {
console.log(
`info: ${msg.toString()} | ${msg.length} bytes from ${info.address}:${
info.port
}`
);
const response = {
description: '您好我收到了您的请求',
serverPort: conf.port,
timestamp: new Date().toJSON(),
body: {
message: msg.toString(),
fromIP: info.address,
fromPort: info.port,
},
};
const data = Buffer.from(JSON.stringify(response));

// 回应客户端消息
server.send(data, info.port, info.address, (error, bytes) => {
if (error) {
console.log('UDP 发送错误', error);
client.close();
return;
}
console.log('UDP 已发送消息', bytes);
});
});

// 监听器,当 UDP 服务器套接字开始监听端口时会触发这个事件
server.on('listening', () => {
const { port, family, address: ipAddress } = server.address(); // 获取服务器监听的地址信息,返回一个对象。
console.log('开始监听');
console.log('端口', port);
console.log('ip 地址', ipAddress);
console.log('地址族 IP4/IP6', family);
});

// 接收关闭事件
server.on('close', () => {
console.log('UPD 服务已经关闭');
});

// 绑定服务器到指定端口
server.bind(conf.port);

实现服务端的 UDP udpClient.js

const udp = require('dgram');
const conf = require('./config.json');

const client = udp.createSocket('udp4');

const data = Buffer.from('Hi, 让我看看您是否有响应');

client.on('message', (msg, { address, port }) => {
// 这个要加个判断,不然会接收全网 6666 端口的信息
if (address === conf.serverHost && port === conf.port) {
console.log('服务端的响应' + msg.toString());
console.log(
'服务端信息 %d bytes from %s:%d\n',
msg.length,
info.address,
info.port
);
}
});

const msgs = [Buffer.from('o1o1'), Buffer.from('收到请回答哦')];

client.send(msgs, conf.port, conf.host, error => {
if (error) {
console.log('发送失败');
client.close();
return;
}
console.log('发送完成');
});

运行 udpServer.js

❯ node udpServer.js

结果

❯ node udp_server.js
开始监听
端口 6666
ip 地址 0.0.0.0
地址族 IP4/IP6 IPv4

运行 udpClient.js

❯ node udpClient.js

结果

❯ node udp_client.js
发送完成
服务端的响应{"description":"您好我收到了您的请求","serverPort":6666,"timestamp":"2024-08-01T10:27:32.120Z","body":{"message":"o1o1收到请回答哦","fromIP":"127.0.0.1","fromPort":49160}}
服务端信息 187 bytes from 127.0.0.1:6666

服务端结果

❯ node udp_server.js
开始监听
端口 6666
ip 地址 0.0.0.0
地址族 IP4/IP6 IPv4
info: o1o1收到请回答哦 | 22 bytes from 127.0.0.1:49160
UDP 已发送消息 187

其他

KCP 如何使用 教程