Parsing 为分隔符分隔的块缓冲数据

Parsing 为分隔符分隔的块缓冲数据,parsing,buffer,delimiter,Parsing,Buffer,Delimiter,有一个问题我想了很久,我希望有人能给我一个答案,让我安心 让我们假设我有一个输入流(如文件/套接字/管道),并希望解析传入的数据。让我们假设每个传入数据块都被一条换行线分割,就像大多数常见的internet协议一样。该应用程序也可以解析html、xml或任何其他智能数据结构。关键是数据被分隔符而不是固定长度分割成逻辑块。如何缓冲数据以等待分隔符出现 答案似乎很简单:只要有一个足够大的字节/字符数组来容纳整个内容 但是如果分隔符出现在缓冲区已满之后呢?这实际上是一个关于如何在固定大小的块中适应动态

有一个问题我想了很久,我希望有人能给我一个答案,让我安心

让我们假设我有一个输入流(如文件/套接字/管道),并希望解析传入的数据。让我们假设每个传入数据块都被一条换行线分割,就像大多数常见的internet协议一样。该应用程序也可以解析html、xml或任何其他智能数据结构。关键是数据被分隔符而不是固定长度分割成逻辑块。如何缓冲数据以等待分隔符出现

答案似乎很简单:只要有一个足够大的字节/字符数组来容纳整个内容

但是如果分隔符出现在缓冲区已满之后呢?这实际上是一个关于如何在固定大小的块中适应动态数据块的问题。我真的只能想到几个选择:

  • 需要时增加缓冲区大小。这可能需要大量内存重新分配,并可能导致精心编制的流耗尽资源(或者,在套接字的情况下,甚至可能是拒绝服务,我们希望保护自己免受耗尽攻击,并丢弃试图耗尽资源的连接……而攻击者开始发送虚假的、过大的数据包来触发保护)

  • 开始使用循环缓冲区覆盖旧数据。可能不是理想的方法,因为逻辑块将变得不完整

  • 当缓冲区已满时转储新数据。但是,这样将永远找不到分隔符,因此此选项显然不是一个好选项

  • 只需将固定大小的缓冲区设置得非常大,并假设所有传入的逻辑数据块都在其范围内…如果它已填充,只需将完整的缓冲区解释为逻辑块

  • 在这两种情况下,我觉得我们必须假设逻辑块永远不会超过某个特定的大小

    关于这个主题有什么想法吗?显然,一定有办法,因为高级语言通过
    readLine()
    stream方法提供了某种缓冲机制

    有什么“最好的方法”来解决这个问题吗?还是总是有一个折衷的办法?我真的很感激关于这个主题的所有想法和想法,因为每当我需要编写某种类型的解析器时,这个问题一直困扰着我。

    选项(2)和(3)都不存在,因为在这两种情况下都会丢失数据。选项(4)一个巨大的固定大小的缓冲区并不能解决这个问题,因为不可能知道什么大小足够大?是所有物理内存+交换空间+已知世界中所有磁盘中可用的可用空间吗

    调整缓冲区的大小看起来是最好的解决方案。假设realloc的大小是原来的两倍,然后继续写入。总是有可能出现一个特殊构造的流,比如DoS,试图破坏系统。我的第一个想法是将缓冲区的最大大小设置为任意大。但是,如果我们能够做到这一点,我们可以将因此,对我来说,调整缓冲区的大小似乎是最好的选择

  • 如果协议或您没有为每个块的长度定义上限,那么我看不出如何防止内存耗尽边缘情况

  • 假设使用固定大小的块有一个上限,对于大小合理的限制来说似乎是一个很好的方法

  • 如果限制足够高,单个固定缓冲区将效率低下,那么我建议使用一个在内部实现为固定大小缓冲区链接列表的数据结构


  • 为什么要等待开始处理

    一般来说,备选方案4是合理的。然而,它不需要“假设”,而需要一个定义。您只需声明块小于8K,并用它来完成。这并不困难

    此外,还有备选方案5:开始处理部分缓冲区。除非您设计了一个真正病态的协议,在数据块的最后发送关键数据,否则这种方法是有效的


    HTML、XML、JSON/YAML等都可以增量解析。你不需要一个delimeter来进行有用的处理。

    通常有两种技术可以实现这一点

    1) 我认为readline使用的是—如果缓冲区填满,则返回的数据末尾没有分隔符

    2) 当缓冲区填充时,请记住它已填充,继续读取,直到获得分隔符并报告错误(或按缓冲区大小截断记录)