我有一个更大的缓冲区,我正在尝试将其作为数据包发送。 Nodejs 将缓冲区分割成更小的(65k 数据包)。一旦客户端收到它们,我如何确保数据包组合在一起并有效地将它们重新组合到缓冲区中?
几乎用这个作为测试:
// tcp socket
var buf = Buffer.alloc(265000);
socket.write(buf);
然后在客户端,我需要以某种方式将 65k 数据包组合回缓冲区。
谢谢
请您参考如下方法:
TCP 可以自由地将线路上的数据分解成任意大小的数据包。根据不同的实现或物理传输,大小可以不同。您无法确切知道这将如何发生,也不应该具体取决于它是如何实现的。它甚至可能会根据您的数据采用的路径而有所不同。
此外,.on('data', ...)
事件只是为您提供到目前为止已到达的所有数据。虽然数据包的顺序得到保证,但不能保证如果您写入一组特定的字节,它们都会在同一个 data
事件中到达。它们可以被分解成更小的碎片,并且可能以更小的碎片形式到达。当 TCP 之上没有真正的协议(protocol)时,这就是 TCP 较低级别上发生的情况。
因此,如果您通过 TCP 发送大量数据,则必须发明自己的协议(protocol)才能知道何时获得整组数据。有多种不同的方案可以实现此目的。
分隔符。某种分隔符,不会出现在实际数据中,表示一组数据的结束。您读取并解析数据,直到获得分隔符,然后您就知道您拥有可以处理的完整数据集。 HTTP 协议(protocol)使用换行符作为分隔符。有时使用零字节作为分隔符。
先发送长度。对于二进制数据,通常先发送数据的长度,然后接收者知道他们正在读取多少字节的数据,直到获得完整的数据集.
现有协议(protocol)。像 webSocket 协议(protocol)这样的协议(protocol)可以让您发送任意大小的消息,它会自动将它们包装成包含长度信息的数据包,以便可以自动为您重新组合它们到原始数据集,而无需您自己执行此操作。还有数千种其他协议(protocol),其中一种可能非常适合您的需求,您只需使用现有的实现即可,而无需编写自己的实现。
如果您有某种机制知道何时收到一组完整的数据,那么您可以设置 data
事件处理程序来读取数据,将其收集到缓冲区中并观察结束数据(使用您选择的任何机制)。当您看到一组末尾时,您可以将其与可能在其之后到达的任何其他数据分开,然后对其进行处理。
因此,假设您使用零字节作为分隔符,并且您已确保零不能也不会出现在实际数据中。然后,您将设置一个数据
处理程序,如下所示:
let accumulatedData = Buffer.alloc(0);
socket.on('data', data => {
// check for delimiter character
let offset = data.indexOf(0);
if (offset !== -1) {
// get the whole message into one Buffer
let msg = Buffer.concat(accumulatedData, data.slice(0, offset));
// put rest of data into the accumulatedData buffer as part of next piece of data
// skip past the delimiter
accumulatedData = data.slice(offset + 1);
// emit that we now have a whole msg
socket.emit('_msg', msg);
} else {
// no delimiter yet, just accumulate the data
accumulatedData = Buffer.concat(accumulatedData, data);
}
});
// if any accumulated data still here at end of socket
// notify about it
// this is optional as it may be a partial piece of data (no delimiter)
socket.on('end', () => {
if (accumulatedData.length) {
socket.emit('_msg', accumulatedData);
}
});
// this is my own event which is emitted when a whole message is available
// for processing
socket.on('_msg', msg => {
// code here to process whole msg
});
注意:此实现删除了消息末尾的分隔符