conn.Read常读不全因TCP是流式协议,只保证最多读len(buf)字节;需用io.ReadFull读固定头、bufio.Scanner处理换行但须设缓冲上限;TLV等复杂协议才需自维护per-connection缓冲区。
conn.Read 为什么经常读不全?
因为 conn.Read 是底层 TCP 流读取,它只承诺“最多读 len(buf) 字节”,不保证一次把一个逻辑消息读完。你发了 "HELLO\n",它可能第一次返回 "HELLO"(n=5),第二次才返回 "\n"(n=1);也可能把三次发送拼成一次返回。这不是 bug,是 TCP 协议本身的流式特性。
- 永远用
buffer[:n]取有效数据,别直接用整个buffer - 遇到
err == io.EOF表示对方关闭连接,不是错误,该退出循环 - 如果只读固定长度头(比如 4 字节包长),必须用
io.ReadFull,否则可能只读到 2 字节就返回,导致后续解析崩溃
用 bufio.Scanner 处理换行分隔协议够用吗?
够用,但有隐含限制:它默认按 \n 切分,且内部缓冲区无上限。若客户端发超长行(比如 10MB 日志),scanner.Scan() 会卡住或 OOM。
- 务必调用
scanner.Buffer(make([]byte, 4096), 1 设定初始和最大缓冲区大小 - 若协议用
\r\n或自定义分隔符(如"###"),需用scanner.Split()自定义分割函数 - 返回的
scanner.Text()包含换行符前的内容,不含\n;但scanner.Bytes()返回的是带换行符的原始切片,注意清理
如何安全解析带长度前缀的二进制包?
这是生产环境最推荐的方式,但手写容易漏掉关键校验点。核心是“先读头、再读体”,两步都必须用 io.ReadFull,不能用普通 Read。