【问题标题】:Reading from a socket into a buffer从套接字读取到缓冲区
【发布时间】:2012-12-07 08:56:14
【问题描述】:

这个问题可能看起来很简单,但我认为它并不是那么微不足道。或者也许我想多了,但我还是想知道。

假设我们必须从 TCP 套接字读取数据,直到遇到一些特殊字符。数据必须保存在某个地方。我们不知道数据的大小,所以我们不知道我们的缓冲区有多大。在这种情况下有哪些可能的选择?

  1. 随着更多数据到达使用realloc 扩展缓冲区。这种方法提出了一些问题。使用 realloc 对性能有何影响?它可能会移动内存,所以如果缓冲区中有很多数据(并且可能有很多数据),我们将花费大量时间移动字节。我们应该将缓冲区大小扩展多少?我们每次都加倍吗?如果是,那么所有浪费的空间呢?如果我们稍后以较小的大小调用 realloc,它会截断未使用的字节吗?

  2. 以恒定大小的块分配新缓冲区并将它们链接在一起。 这与 C++ 标准库中的双端队列容器非常相似,允许快速附加新数据。这也有一些问题,比如我们应该做多大的块以及如何处理未使用的空间,但至少它具有良好的性能。

您对此有何看法?这两种方法哪个更好?也许还有其他我没有考虑过的方法?

附:

就个人而言,我更倾向于第二种解决方案,因为我认为如果我们“回收”块而不是每次需要块时都进行动态分配,它可以做得非常快。我能看到的唯一问题是它会损害局部性,但我认为这对我的目的(处理类似 HTTP 的请求)来说并不是非常重要。

谢谢

【问题讨论】:

  • 最简单的方法是在标头中包含请求大小。这可能会也可能不会,具体取决于您使用的协议。
  • 很遗憾,这是不可能的
  • 我个人使用 std::vector 并推回数据,直到我得到所有数据或在你的情况下遇到一些特殊字符。这对我来说是最简单的,到目前为止对我很有帮助。

标签: c++ sockets memory buffer


【解决方案1】:

我更喜欢第二种变体。您也可以考虑只使用一个原始缓冲区并在从套接字接收另一组数据之前处理接收到的数据,即在遇到特殊字符之前开始处理数据。

在任何情况下,我都不建议使用原始内存和 realloc,而是使用具有自己重新分配功能的 std::vector,或者使用 std::array 作为固定大小的缓冲区。

您可能还对 Boost.Asio 的 socket_iostreams 感兴趣,它在原始缓冲区之上提供了另一个抽象层。

【讨论】:

  • std::vector<> 用于网络缓冲区会对性能产生负面影响:它会将即将被从套接字读取的数据替换的内存清零。
【解决方案2】:

方法 2 听起来更好,但是可能会对您的解析器产生重大影响......即,一旦您找到您的特殊标记,在解析 HTTP 请求时处理非连续缓冲区可能最终比重新分配一个更昂贵或更复杂大缓冲区(方法 1)。 Net-net:如果您的解析器很简单,请使用 2,否则请使用 1。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-09-25
    • 2021-07-31
    • 1970-01-01
    • 2016-04-22
    • 1970-01-01
    • 2020-09-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多