我正在编写一个小型 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 字节读入空缓冲区,然后处理数据。
问题发生在:
- 一帧数据比它试图从 tcp 连接读入的缓冲区大。在这种情况下,我无法处理数据,直到收到其余数据(但接收缓冲区已被之前的数据占用)。
- 当缓冲区包含一个半帧的数据时,我需要处理第一帧,同时保留不完整的帧供以后使用...在这种情况下,我需要从缓冲区中移除已处理的部分,然后移动不完整的部分,以便为框架的其余部分留出空间。
这两种情况都可能需要重新分配和复制数据,这可能是一项代价高昂的操作?此外,除了扩展缓冲区之外,我不知道如何处理大于缓冲区的帧......但是不断增加的缓冲区可能会导致性能问题和拒绝服务。最后但并非最不重要的一点是,我对 Golang 的标准库的了解不够好,无法知道是否有明确构建的包来处理这些情况。
所以我的问题是:
- 是否有处理这些情况的最佳实践?
- 是否有任何 golang 包可以为我完成部分或大部分工作?
谢谢。
最佳答案
byte slice 应该支持非常优化的大小调整(即保留比需要更多的字节,如果可以则不复制,呈指数增长,复制代码不是用 go 编写的,而是运行时的一部分,等等)。
因此您可以使用 append
并查看其工作原理。
另一种更惯用的方法是使用 bufio.Reader
来包装连接,它会自动处理所有这些。我已经在我编写的 tcp 服务器中使用它并且速度非常快。你只需要做:
r := bufio.NewReader(conn)
然后您可以读取直到分隔符或给定的字节数(如果您事先知道)。
关于tcp - Go:有效处理通过 TCP 接收的碎片数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22218838/