有一个问题,我一直想知道多年,我希望有人可以给我一个安息的答案。
假设我有一个输入流(如文件/套接字/管道)并想要解析传入的数据。假设每个传入数据块都被换行符分割,就像大多数常见的互联网协议一样。这个应用程序也可以解析html,xml或任何其他智能数据结构。关键是数据通过分隔符而不是固定长度分成逻辑块。如何缓冲数据以等待分隔符出现?
答案似乎很简单:只需要一个足够大的byte / char数组来适应整个事情。
但是如果分隔符在缓冲区已满后出现怎么办?这实际上是关于如何在固定大小的块中拟合动态数据块的问题。我只能想到几个选择:
需要时增加缓冲区大小。这可能需要大量内存重新分配,并且可能导致特制流的资源耗尽(或者甚至可能在套接字的情况下拒绝服务,我们希望保护自己免受耗尽攻击并丢弃试图耗尽资源的连接......和攻击者开始发送假的,超大的数据包以触发保护。)
使用循环缓冲区开始覆盖旧数据。也许不是理想的方法,因为逻辑块会变得不完整。
缓冲区已满时转储新数据。但是,这种分隔符永远不会被找到,所以这个选择显然不是一个好选择。
只需使固定大小的缓冲区大,并假设所有传入的逻辑数据块都在其范围内......如果它已填满,只需将整个缓冲区解释为逻辑块...
在任何一种情况下,我觉得我们必须假设逻辑块永远不会超过一定的大小......
有关此主题的任何想法?显然必须有一种方法,因为更高级别的语言使用readLine()
流方法提供某种缓冲机制。
有没有“最好的方法”来解决这个问题,还是总是需要权衡?我非常感谢关于这个主题的所有想法和想法,因为每当我需要编写某种解析器时,这个问题一直困扰着我。
答案 0 :(得分:2)
这通常有两种技术
1)我认为readline使用的是 - 如果缓冲区填充返回数据而没有末尾的分隔符
2)当缓冲区填满时,记住填充,继续读取,直到你得到分隔符并报告错误(或截断缓冲区大小的记录)
答案 1 :(得分:0)
选项(2)和(3)在两种情况下都会丢失数据。一个巨大的固定大小缓冲区的选项(4)无法解决问题,因为它不可能知道什么尺寸足够大?它是所有物理内存+交换空间+已知Universe中所有磁盘中可用的可用空间吗?
调整缓冲区大小看起来是最好的解决方案。将realloc称为两倍大小并继续写入。总是有可能像DoS那样试图打倒系统的特殊构造流。我的第一个想法是设置一个任意大的大小作为缓冲区的max_size。但是,如果我们可以这样做,我们可以将其设置为大缓冲区的大小。因此,调整缓冲区大小对我来说是最好的选择。
答案 2 :(得分:0)
如果协议或您没有为每个块的长度定义上限,那么我看不出如何防止内存耗尽边缘情况。
假设使用固定大小的块存在上限似乎是合理大小限制的好方法。
如果限制足够高,单个固定缓冲区效率低,那么我建议使用内部实现的数据结构作为固定大小缓冲区的链接列表。
答案 3 :(得分:0)
为什么还要等到开始处理?
通常替代方案4是声音。然而,它不需要“假设”,而是一个定义。您只需声明块小于8K并完成它。这并不困难。
此外,还有替代方案5:开始处理部分缓冲区。除非您设计了一个真正的病态协议,在块的最末端发送关键数据,否则这是有效的。
HTML,XML,JSON / YAML等都可以逐步解析。您没有要求分隔符来执行有用的处理。