data是什么数据结构?TCP是一个字节流,如果我想在这个字节流中拆分出不同的独立消息,该怎么做?
const net = require('net');
const clients = [];
// index.js
console.log('Aggregation Engine Agent is running.............................................................!');
// // 持续运行进程
// setInterval(() => {
// console.log('>> Aggregation Engine Agent << running...');
// }, 1000);
// 创建TCP服务器
const server = net.createServer((socket) => {
// the function will be run when a client connects to the server
console.log('>>>>> >>>> >>> >> > ----------------- New client connected');
// 将客户端连接保存到数组中
clients.push(socket);
// // 监听客户端发送的数据
// socket.on('connect', (data) => {
// console.log('>>>>> >>>> >>> >> > connected data:', data.toString());
// // 你可以在这里处理客户端发来的数据
// });
// 监听客户端发送的数据
socket.on('data', (data) => {
console.log('Received data ######################################:', data.toString());
// 你可以在这里处理客户端发来的数据
});
// 监听客户端关闭连接
socket.on('end', () => {
console.log('Client disconnected');
// 从数组中删除已断开连接的客户端
const index = clients.indexOf(socket);
if (index !== -1) {
clients.splice(index, 1);
}
});
// 监听错误事件
socket.on('error', (err) => {
console.error('Socket error:', err);
});
});
// 设置服务器监听的端口和主机
const PORT = 18760;
// const HOST = '127.0.0.1';
const HOST = '0.0.0.0'; // 局域网内允许所有客户端连接
server.listen(PORT, HOST, () => {
console.log(`TCP server listening on ${HOST}:${PORT}`);
});
上面的这个nodejs项目代码文件,关注 socket.on('data', (data) => { /* ... */ }); 部分。
data是什么数据结构?TCP是一个字节流,如果我想在这个字节流中拆分出不同的独立消息,该怎么做?
eeeeeeeeeeeeeeeeeeeeeeeeeeee
你对socket.on('data', ...)
部分的理解是正确的。这里,data
是一个 Buffer 对象,它表示从客户端接收到的原始字节流。
1. data
的数据结构:
在 Node.js 中,socket.on('data', ...)
中的 data
是一个 Buffer,这是 Node.js 用来处理原始二进制数据的对象。你可以将它看作一个字节数组,可以通过 Buffer
的方法来操作。
socket.on('data', (data) => {
console.log('Received data:', data); // data是一个Buffer对象
console.log('Data as string:', data.toString()); // 转换成字符串
});
2. 如何拆分字节流中的消息:
TCP 是基于字节流的协议,客户端发送的数据不会被自动拆分成消息。要拆分字节流,你需要自己定义一种消息边界标识。这可以通过多种方式完成,以下是一些常见的方法:
方法 1:使用固定长度的消息
假设每个消息的大小是固定的,你可以每次读取固定长度的字节来获取完整的消息。
例如,假设每个消息是 10 字节:
socket.on('data', (data) => {
// 假设每条消息是10字节
let messageLength = 10;
let offset = 0;
while (offset + messageLength <= data.length) {
const message = data.slice(offset, offset + messageLength);
console.log('Received message:', message.toString());
offset += messageLength;
}
});
方法 2:使用消息长度作为前缀
你可以定义每条消息的前几个字节作为消息长度的标识。比如,每个消息前面加上 4 个字节表示消息的长度,然后按照这个长度来拆分消息。
示例:
假设消息的前 4 个字节表示消息的长度:
socket.on('data', (data) => {
let offset = 0;
// 每次读取 4 个字节的长度字段
while (offset + 4 <= data.length) {
const messageLength = data.readUInt32BE(offset); // 读取消息长度(大端模式)
offset += 4;
if (offset + messageLength <= data.length) {
const message = data.slice(offset, offset + messageLength);
console.log('Received message:', message.toString());
offset += messageLength;
} else {
// 如果剩余的数据不足以完成一条消息,等待更多数据
break;
}
}
});
方法 3:使用特定的分隔符
如果消息是文本数据,你可以使用特定的分隔符来分隔每条消息。例如,可以使用换行符(\n
)作为分隔符,将字节流按照换行符拆分成独立的消息。
socket.on('data', (data) => {
let message = data.toString();
// 使用换行符分隔消息
let messages = message.split('\n');
messages.forEach((msg) => {
if (msg.trim()) { // 排除空消息
console.log('Received message:', msg);
}
});
});
3. 如何选择方法:
- 固定长度:适用于消息长度固定的情况。
- 消息长度前缀:适用于你知道每条消息长度的情况,或者长度是动态变化的,但有前缀指示长度。
- 分隔符:适用于文本数据,并且每条消息由某种明确的分隔符(如换行符)分隔的情况。
4. 如何确保完整的消息:
TCP是流式的,这意味着你不能保证每次接收到的数据都是完整的消息。如果你正在拆分数据,确保处理以下情况:
- 数据碎片:一条消息可能会被拆成多个数据块(例如,一次
data
事件可能只接收到部分消息)。 - 消息重组:你可能需要缓冲不完整的消息,等待剩余的数据到来,直到你能将整个消息拼凑出来。
5. 示例代码:使用长度前缀来拆分消息
这是一个综合的示例,使用前缀来表示消息的长度,并处理流式数据:
let buffer = Buffer.alloc(0);
socket.on('data', (data) => {
buffer = Buffer.concat([buffer, data]); // 将新接收到的数据附加到缓冲区
// 处理所有完整的消息
while (buffer.length >= 4) { // 至少需要4个字节来读取长度
const messageLength = buffer.readUInt32BE(0); // 读取消息长度(大端模式)
// 如果缓冲区的长度大于等于消息长度 + 4字节(消息长度字段)
if (buffer.length >= messageLength + 4) {
const message = buffer.slice(4, 4 + messageLength); // 提取消息内容
console.log('Received message:', message.toString());
// 更新缓冲区,移除已处理的消息
buffer = buffer.slice(4 + messageLength);
} else {
// 如果数据不完整,等待更多数据
break;
}
}
});
这样,你可以确保消息在流中被正确拆分,并且处理过程中不会丢失数据。
如果你有其他问题或想深入探讨,请随时告诉我!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?