如何有效发送大数据包/合并较小的数据包?

时间:2019-07-12 15:42:41

标签: node.js

我尝试将较大的缓冲区作为数据包发送。 Nodejs将缓冲区拆分为较小的(65k数据包)。客户端收到它们后,如何确保这些数据包在一起并将它们有效地重新组合到缓冲区中?

将其用作测试:

// tcp socket
var buf = Buffer.alloc(265000);
socket.write(buf);

然后在客户端,我需要以某种方式将65k数据包组合回一个缓冲区。

谢谢

2 个答案:

答案 0 :(得分:1)

TCP可以自由地将网络上的数据分解为任何大小的数据包。大小可以根据不同的实现或物理传输而有所不同。您无法确切知道这将如何发生,并且不应完全取决于它是如何实现的。甚至可能取决于数据采用的路由。

此外,.on('data', ...)事件仅向您提供到目前为止已到达的所有数据。尽管可以保证数据包的顺序,但不能保证如果您写入一组字节,它们将全部在相同的data事件中到达。它们可以分成较小的碎片,也可以分成较小的碎片。当您在TCP之上没有实际协议时,就会在较低级别的TCP上发生这种情况。

因此,如果您要通过TCP发送大量数据,则必须发明自己的协议才能知道何时有完整的数据集。有很多不同的方案可以做到这一点。

  1. 定界符。某种定界符在实际数据中不会出现,它指示一组数据的结尾。您读取并解析数据,直到获得定界符,然后才知道您拥有可以处理的完整数据集。 HTTP协议使用换行符作为分隔符。有时,零字节用作分隔符。

  2. 先发送长度。对于二进制数据,通常先发送数据长度,然后接收者知道他们正在读取多少字节数据,直到拥有整套数据为止。

  3. 现有协议。类似于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