0

0

Golang如何处理TCP粘包问题_Golang网络通信常见坑

P粉602998670

P粉602998670

发布时间:2026-01-31 13:34:02

|

678人浏览过

|

来源于php中文网

原创

TCP是字节流协议,conn.Read不保证按发送边界返回数据,需用4字节大端长度头+io.ReadFull处理粘包、半包;禁用分隔符法和共享缓冲区。

golang如何处理tcp粘包问题_golang网络通信常见坑

为什么conn.Read一读就错:TCP根本不管“包”是什么

Go 的 net.Conn字节流接口,Read 返回的只是当前缓冲区里凑够的字节数,和你 Write 几次、每次写多少完全无关。客户端连发 "hi""ok",服务端一次 Read 可能拿到 "hiok";或者只拿到 "h",下一次才读到 "iok"——这不是 bug,是 TCP 的设计使然。

  • 别用 time.SleepSetReadDeadline “等一会儿再读”,这既不可靠又拖慢吞吐
  • 别假设 Read 会返回完整业务消息,哪怕你只 Write 了一次
  • 别忽略 Read 返回的 n 值,它可能远小于你申请的 buffer 长度

最稳的方案:用 4 字节大端长度头 + io.ReadFull

在每条消息前加 4 字节 uint32(网络字节序),先读头、再按长度读体,天然兼容粘包、半包、多包合并。比换行符或固定长度更通用,也比自定义分隔符更安全——不用操心业务数据里有没有 "\n""[END]"

  • 发送端必须用 binary.BigEndian.PutUint32 写头,不是 LittleEndian,跨语言通信时尤其关键
  • 接收端必须用 io.ReadFull 读头和读体,它会自动循环调用 Read 直到填满,避免手动处理 EOFshort read
  • 头部统一用 4 字节(uint32),覆盖绝大多数场景;8 字节太重,2 字节上限仅 64KB,容易溢出
func readMessage(conn net.Conn) ([]byte, error) {
    var header [4]byte
    if _, err := io.ReadFull(conn, header[:]); err != nil {
        return nil, err
    }
    msgLen := binary.BigEndian.Uint32(header[:])
    data := make([]byte, msgLen)
    if _, err := io.ReadFull(conn, data); err != nil {
        return nil, err
    }
    return data, nil
}

别踩这些坑:bufio.ScannerReadBytes 不是解药

bufio.Scanner 默认按 \n 切分,看起来方便,但只要业务数据含未转义换行(比如用户发的 JSON、带表情的日志、代码块),就会提前截断;ReadBytes 同理,它只找第一个分隔符就停,不保证前面没被截断、后面没多包。

  • Scanner 必须配 SplitFunc 自定义逻辑,且要处理缓冲区残留和边界重叠
  • ReadBytes 返回的切片仍需校验完整性,它不解决“半包”问题
  • 二进制数据、加密 payload、protobuf 序列化结果一律禁用分隔符法

缓冲区管理必须每连接独享,不能全局复用

多个 goroutine 并发读同一连接时,如果共用一个 bytes.Buffer 或切片,会出现数据错乱。常见错误是把 buf 声明在 for 循环外,然后在 handle 中反复 WriteToRead

论论App
论论App

AI文献搜索、学术讨论平台,涵盖了各类学术期刊、学位、会议论文,助力科研。

下载

立即学习go语言免费学习笔记(深入)”;

  • 每个连接应持有自己的 bytes.Buffer 实例,或至少用局部变量管理未解析完的数据
  • 解包逻辑必须循环处理缓冲区:一次 Read 可能含多个完整包 + 一个半包,不能读完就丢弃剩余字节
  • 遇到半包时,用 buf.Next(n) 消费已处理部分,保留尾部供下次续读

真正麻烦的从来不是协议怎么定,而是把长度头读全、把 body 读满、把半包留对——这三个动作必须嵌入 I/O 生命周期,漏掉任意一环,上线后第一条含 emoji 的消息就能让服务开始吐错包。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
golang如何定义变量
golang如何定义变量

golang定义变量的方法:1、声明变量并赋予初始值“var age int =值”;2、声明变量但不赋初始值“var age int”;3、使用短变量声明“age :=值”等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

182

2024.02.23

golang有哪些数据转换方法
golang有哪些数据转换方法

golang数据转换方法:1、类型转换操作符;2、类型断言;3、字符串和数字之间的转换;4、JSON序列化和反序列化;5、使用标准库进行数据转换;6、使用第三方库进行数据转换;7、自定义数据转换函数。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

229

2024.02.23

golang常用库有哪些
golang常用库有哪些

golang常用库有:1、标准库;2、字符串处理库;3、网络库;4、加密库;5、压缩库;6、xml和json解析库;7、日期和时间库;8、数据库操作库;9、文件操作库;10、图像处理库。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

343

2024.02.23

golang和python的区别是什么
golang和python的区别是什么

golang和python的区别是:1、golang是一种编译型语言,而python是一种解释型语言;2、golang天生支持并发编程,而python对并发与并行的支持相对较弱等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

210

2024.03.05

golang是免费的吗
golang是免费的吗

golang是免费的。golang是google开发的一种静态强类型、编译型、并发型,并具有垃圾回收功能的开源编程语言,采用bsd开源协议。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

396

2024.05.21

golang结构体相关大全
golang结构体相关大全

本专题整合了golang结构体相关大全,想了解更多内容,请阅读专题下面的文章。

240

2025.06.09

golang相关判断方法
golang相关判断方法

本专题整合了golang相关判断方法,想了解更详细的相关内容,请阅读下面的文章。

194

2025.06.10

golang数组使用方法
golang数组使用方法

本专题整合了golang数组用法,想了解更多的相关内容,请阅读专题下面的文章。

478

2025.06.17

2026赚钱平台入口大全
2026赚钱平台入口大全

2026年最新赚钱平台入口汇总,涵盖任务众包、内容创作、电商运营、技能变现等多类正规渠道,助你轻松开启副业增收之路。阅读专题下面的文章了解更多详细内容。

32

2026.01.31

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
WEB前端教程【HTML5+CSS3+JS】
WEB前端教程【HTML5+CSS3+JS】

共101课时 | 8.6万人学习

JS进阶与BootStrap学习
JS进阶与BootStrap学习

共39课时 | 3.2万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号