我尝试将较大的缓冲区作为数据包发送。 Nodejs将缓冲区拆分为较小的(65k数据包)。客户端收到它们后,如何确保这些数据包在一起并将它们有效地重新组合到缓冲区中?
将其用作测试:
// tcp socket
var buf = Buffer.alloc(265000);
socket.write(buf);
然后在客户端,我需要以某种方式将65k数据包组合回一个缓冲区。
谢谢
答案 0 :(得分:1)
TCP可以自由地将网络上的数据分解为任何大小的数据包。大小可以根据不同的实现或物理传输而有所不同。您无法确切知道这将如何发生,并且不应完全取决于它是如何实现的。甚至可能取决于数据采用的路由。
此外,.on('data', ...)
事件仅向您提供到目前为止已到达的所有数据。尽管可以保证数据包的顺序,但不能保证如果您写入一组字节,它们将全部在相同的data
事件中到达。它们可以分成较小的碎片,也可以分成较小的碎片。当您在TCP之上没有实际协议时,就会在较低级别的TCP上发生这种情况。
因此,如果您要通过TCP发送大量数据,则必须发明自己的协议才能知道何时有完整的数据集。有很多不同的方案可以做到这一点。
定界符。某种定界符在实际数据中不会出现,它指示一组数据的结尾。您读取并解析数据,直到获得定界符,然后才知道您拥有可以处理的完整数据集。 HTTP协议使用换行符作为分隔符。有时,零字节用作分隔符。
先发送长度。对于二进制数据,通常先发送数据长度,然后接收者知道他们正在读取多少字节数据,直到拥有整套数据为止。
现有协议。类似于webSocket协议,您可以发送任何大小的消息,并且它将自动将它们包装到包含有关长度信息的数据包中,以便可以自动为您重新组合转换为原始数据集,而无需您自己执行。还有成千上万种其他协议,其中一种可能非常适合您的需求,您可以使用现有的实现而不必编写自己的实现。
您可以使用某种机制来知道何时收到完整的数据集,然后设置data
事件处理程序以读取数据,将其收集到缓冲区中并观察数据的结束(使用您选择的任何一种机制)。当您看到集合的结尾时,可以将其与可能在集合之后到达的其他任何数据分开,然后对其进行处理。
因此,假设您使用零字节作为定界符,并且确保在真实数据中不能也不会出现零。然后,您将像这样设置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
});
注意:此实现从味精的末尾删除定界符
答案 1 :(得分:0)
Nodejs不会拆分数据; TCP / IP是。 IP有效负载中允许的最大数据量为64Kb。这就是为什么您的数据包被拆分(分段)的原因。
这也意味着TCP / IP将在接收端将数据组合在一起。这就是为什么您不必重组REST请求或网站的原因。这些全部由较低的网络层处理。
您可能想看看这个example。您可以编辑createServer()
函数来发送更多数据,如下所示:
var server = net.createServer(function(socket) {
let buf = Buffer.alloc(265000);
for (var i = 0; i < 264900; i++) {
buf[i] = 'E';
}
buf[264900] = '\r'; // newline
buf[264901] = '\n';
buf[264902] = 0; // string terminator
socket.write(buf);
socket.pipe(socket);
});
以上内容(连同摘要的其他代码)将使用包含264900'E和换行符的字符串来响应任何请求。
现在,您可以使用netcat(如果在Linux上)来接收您的请求:
$ netcat 127.0.0.1 1337
EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE ... etc
缓冲区可以包含任何内容,并且仍将全部传输。字符串很容易演示。
结论:让网络来完成这项工作。您将需要读取客户端上的传入缓冲区,并将其保存到其自己的本地缓冲区中,但仅此而已。
进一步阅读:
https://nodejs.org/api/net.html#net_socket_write_data_encoding_callback https://techterms.com/definition/packet