Go:有效处理通过TCP接收的碎片数据

时间:2014-03-06 08:22:23

标签: tcp go buffer

我正在编写一个小型tcp服务器,它只能读取数据,解析接收数据(动态长度帧)并处理这些帧。请考虑以下代码:

func ClientHandler(conn net.Conn) {
    buf := make([]byte, 4096)
    n, err := conn.Read(buf)
    if err != nil {
        fmt.Println("Error reading:", err.Error())
        return
    }
    fmt.Println("received ", n, " bytes of data =", string(buf))
    handleData(buf)

这几乎是我的代码的本质。我将X字节读入空缓冲区,然后处理数据。

问题发生在:

  1. 数据帧大于它尝试从tcp连接读入的缓冲区。在这种情况下,我无法处理数据,直到我收到其余数据(但接收缓冲区已经被先前的数据占用)。
  2. 当缓冲区包含一个半帧的数据时我需要处理第一帧,同时保留不完整的帧以供以后使用...在这种情况下我需要从缓冲区中删除处理过的部分,然后移动不完整的部分,以便框架的其余部分有空间。
  3. 这两种情况都可能需要重新分配和复制数据,这可能是一项代价高昂的操作?此外,除了扩展缓冲区之外,我对如何处理大于缓冲区的帧没有任何想法......但是,不断增加的缓冲区可能会导致性能问题和拒绝服务。最后,但并非最不重要的是,我不知道Golang的标准库是否足以知道是否有任何明确构建的包用于处理这些情况。

    所以我的问题是:

    1. 是否有处理这些情况的最佳做法?
    2. 是否有任何golang软件包会为我做一些或大部分内容?
    3. 谢谢。

1 个答案:

答案 0 :(得分:6)

字节切片应支持相当优化的大小调整(即保留比所需更多的字节,如果可以的话,不进行复制,指数增长,复制代码不是写入,而是写入运行时的一部分,等等)。

因此您可以使用append并查看其工作原理。

另一种更惯用的方法是使用bufio.Reader来包装连接,它会自动处理所有这些。我已经在我编写的tcp服务器中使用它,它非常快。你这样做:

r := bufio.NewReader(conn)

然后你可以读取,直到分隔符或给定数量的字节,如果你事先知道它。