【问题标题】:Algorithm for fragmenting data into packets将数据分片成数据包的算法
【发布时间】:2015-08-04 16:27:27
【问题描述】:

假设我想将一些数据单元分成数据包(每个数据包的最大大小可以说是 1024 字节)。每个数据单元可以是可变大小的,比如:

a = 20 bytes
b = 1000 bytes
c = 10 bytes
d = 800 bytes

任何人都可以建议任何有效的算法来有效地利用带宽来创建包含此类随机数据的数据包吗?我无法将单个数据单元拆分为字节......它们在一个数据包中完整。

编辑:数据单元的顺序无关紧要!

【问题讨论】:

  • 顺序重要吗(即c必须在a之后的包中)?如果答案是“否” - 这是binpacking problem,这是 NP-Hard。
  • 伙计,是的,是的,是的,你太棒了!把它写成答案,如果你有什么要补充的,我会把它标记为答案!

标签: algorithm networking bin-packing


【解决方案1】:

有几种不同的方法,具体取决于您的要求以及您想花多少时间。正如@amit 在 cmets 中提到的,一般问题是 NP-Hard。但是您可以通过一些简单的更改获得一些的改进。

在我们去之前,你确定你真的需要这样做吗?大多数网络层都有一个数据包大小(或更大)的缓冲区。当您写入网络时,它会将您的数据放入该缓冲区。如果您没有完全填满缓冲区,代码将在发送前短暂延迟。如果您在该延迟期间添加更多数据,则新数据将添加到缓冲区中。缓冲区在填满后或延迟超时到期后发送。

因此,如果您有一个一次向网络写入一个字节的循环,那么您不会创建大量的单字节数据包。

在接收端,最低级别的网络层接收整个数据包,但不能保证您接收数据的调用会收到整个数据包。也就是说,发送方可能会发送一个 800 字节的数据包,但在接收端第一次调用 read 可能只返回 50 或 273 字节。

当然,这取决于您读取数据的级别。如果您谈论的是 Java 或 .NET 之类的东西,其中您与网络堆栈的接口是通过套接字进行的,那么您几乎肯定不能保证对 socket.Read() 的调用将返回整个数据包。

现在,如果你可以保证每次调用 read 都会返回一个完整的数据包,那么最简单的打包方法是将所有内容序列化到一个大缓冲区中,然后以多个 1,024 发送出去个字节的数据包。您需要在第一个数据包的前面创建一个标头,说明将发送的总字节数,以便接收者知道会发生什么。结果将是一堆 1,024 字节的数据包,后面可能跟着一个更小的最终数据包。

如果您想确保数据对象完全包含在单个数据包中,那么您必须执行以下操作:

add a to buffer
if remaining buffer < size of b
    send buffer
    clear buffer
add b to buffer
if remaining buffer < size of c
    send buffer     
    clear buffer
add c to buffer
... etc ...

【讨论】:

  • 吉姆,感谢您的回答!要是生活就这么简单就好了……我正在处理一个需要在应用层进行分段的协议。它封装了两种不同类型的“数据单元”,并将它们发送到一个大小有限的数据包中。并且这些数据单元无法更改。所以我的问题正是装箱问题。此外,像序列化这样的好概念也不起作用……这就是协议的奇怪之处。我只在服务器端工作,所以不能违反规则。
【解决方案2】:

这里有一些简单的 JavaScript 伪代码。数据包将保持有序,带宽将得到最佳使用。

packets = [];

PACKET_SIZE = 1024;
currentPacket = [];

function write(data) {
  var len = currentPacket.length + data.length;
  if(len < PACKET_SIZE) {
    currentPacket = currentPacket.concat(data);
  } else if(len === PACKET_SIZE) {
    packets.push(currentPacket.concat(data));
    currentPacket = [];
  } else { // if(len > PACKET_SIZE) {
    packets.push(currentPacket);
    currentPacket = data;
  }
}
function flush() {
  if(currentPacket.length > 0) {
    packets.push(currentPacket);
    currentPacket = [];
  }
}

write(data20bytes);
write(data1000bytes);
write(data10bytes);
write(data800bytes);
flush();

编辑由于您拥有所有数据块,并且您希望以最佳方式将它们无序打包(bin 打包),因此您离开时尝试了块的每个排列以获得准确的答案或妥协最佳猜测/首次拟合类型算法。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-03-05
    • 2012-10-27
    • 2018-02-12
    • 1970-01-01
    • 1970-01-01
    • 2013-09-02
    • 1970-01-01
    • 2018-04-20
    相关资源
    最近更新 更多