TCP-IP协议与粘包
一、TCP/IP协议
数据封装过程:
![]()
TCP首部、IP首部:
![]()
![]()
二、TCP 粘包
TCP 是面向字节流协议,没有消息边界!UDP 面向报文,不存在粘包
粘包产生原因:
TCP 无消息边界 + 缓冲区缓存 + Nagle 攒包 + IP 分片
1.TCP 本身特性:面向字节流 + 收发缓冲区
TCP 不保留应用层消息边界,数据只是一串连续字节;内核有发送缓冲区、接收缓冲区,数据先放缓冲区,不是调用一次 send 就立刻发一个独立包。
2.发送方:Nagle 算法(重点)
Nagle 会把多次小数据攒起来,合并成一个大报文段一起发送,减少小包数量,提升网络效率 → 多条消息粘在一起(粘包)。
3.接收方缓冲区读取
接收端内核收到数据放接收缓冲区;应用程序 recv 一次读的字节数不确定,一次读可能把多条消息一起读出来。
4.网络链路:IP 分片
数据包太大超过 MTU,网络层会分片传输,一条消息被拆成多片,也就是拆包。
粘包解决方法:
1.固定长度
- 每次消息大小固定;接收方每次固定读对应长度。
- 缺点:浪费流量,短消息也要补齐到固定大小。
2.特殊分隔符(分隔符法)
- 消息末尾加特殊标记(比如\n、\r\n),接收方读到分隔符代表一条消息结束。
- 缺点:消息内容里面不能出现这个分隔符,否则解析错乱。
3.消息头 + 消息体
- 头部固定字节,存放消息体长度(比如前 4 字节表示后面数据有多长),后面跟着真实消息内容;
- 流程:先读头部拿到长度 → 再根据长度读取对应字节的消息体。
- 优点:灵活、稳定,项目最常用。
4.关闭 Nagle 算法(不推荐单独用来解决粘包)
- setsockopt设置 TCP_NODELAY,关闭 Nagle,有数据立刻发。
- 注意:关闭 Nagle 不能根治粘包!只是减少攒包,缓冲区依然会带来粘包,一般配合上面方案一起使用
1.粘包是 TCP字节流特性自带的正常现象,TCP 只管可靠传输字节,不区分应用消息,必须应用层自己做消息边界
2.UDP 不会粘包:UDP 面向报文,一次 sendto 对应一个报文,内核保留报文边界
3.粘包、拆包本质是同一个问题:应用层分不清消息起点终点