猿问

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

我正在编写一个小型 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. 当缓冲区包含一个半帧的数据并且我需要处理第一帧时,同时保留不完整的帧以备后用...在这种情况下,我需要从缓冲区中删除已处理的部分,然后移动不完整的部分框架的其余部分有空间。

这两种情况都可能需要重新分配和复制数据,这可能是一项代价高昂的操作?此外,除了扩展缓冲区之外,我对如何处理大于缓冲区的帧没有任何想法……但是不断增加的缓冲区可能会导致性能问题和拒绝服务。最后,但并非最不重要的是,我不知道 Golang 的标准库是否足够好,无法知道是否有任何明确构建的包来处理这些情况。

所以我的问题是:

  1. 是否有处理这些情况的最佳实践?

  2. 是否有任何 golang 包可以为我完成部分或大部分工作?

谢谢你。


收到一只叮咚
浏览 233回答 1
1回答

慕村9548890

字节切片应该支持非常优化的调整大小(即保留比需要更多的字节,如果可以的话不要复制,呈指数增长,复制代码不是用 go 编写的,而是运行时的一部分,等等)。所以你可以使用append并查看它是如何工作的。另一种更惯用的方法是使用bufio.Reader包装连接,它会自动处理所有这些。我已经在我编写的 tcp 服务器中使用了它,而且速度非常快。你只需要:r := bufio.NewReader(conn)然后您可以读取直到分隔符或给定数量的字节(如果您事先知道的话)。
随时随地看视频慕课网APP

相关分类

Go
我要回答