TCP 粘包处理
TCP通信特点
TCP 是流式协议没有消息边界,客户端向服务器端发送一次数据,可能会被服务器端分成多次收到。客户端向服务器端发送多少数据。服务器端可能一次全部收到。
2.保证传输的可靠性,顺序。
3.TCP拥有拥塞控制,所以数据包可能会延后发送。
没有消息边界:
可以理解为水在一个水管里的流动,我们不知道哪段数据是一个我们需要的完整数据
收发有缓冲区:
比如:当水从一端流到了另一端,我们在收数据的时候,不可能每来一滴水就处理一次,这个缓冲区就相当于有了一个水桶,再接了一定的水之后内核再给数据交到用户空间,这样可以大大提升性能。
什么是 TCP 粘包?
TCP 粘包是指发送方发送的若干包数据 到 接收方接收时粘成一包,从接收缓冲区看,后一包数据的头紧接着前一包数据的尾。
TCP 出现粘包的原因?
发送方:发送方需要等缓冲区满才发送出去,造成粘包
接收方:接收方不及时接收缓冲区的包,造成多个包接收
参考资料:TCP粘包问题分析和解决(全)
Swoole怎么处理粘包
方式1: EOF 结束协议
通过约定结束符,来确定包数据是否发送完毕
开启open_eof_check=true
,并用package_eof
来设置一个完整数据结尾字符,同时设置自动拆分open_eof_split
示例:
注意:
1、 要保证业务数据里不能出现package_eof设置的字符,否则将导致数据错误了。
2、可以手动拆包,去掉
open_eof_split
,自行explode("\r\n", $data)
,然后循环发送
方式2: 固定包头+包体协议
这种方式也非常常见,原理是通过约定数据流的前几个字节来表示一个完整的数据有多长,从第一个数据到达之后,先通过读取固定的几个字节,解出数据包的长度,然后按这个长度继续取出后面的数据,依次循环。
配置示例:
open_length_check:打开包长检测特性
package_length_type:长度字段的类型,固定包头中用一个4字节或2字节表示包体长度。
package_length_offset:从第几个字节开始是长度,比如包头长度为120字节,第10个字节为长度值,这里填入9(从0开始计数)
package_body_offset:从第几个字节开始计算长度,比如包头为长度为120字节,第10个字节为长度值,包体长度为1000。如果长度包含包头,这里填入0,如果不包含包头,这里填入120
package_max_length:最大允许的包长度。因为在一个请求包完整接收前,需要将所有数据保存在内存中,所以需要做保护。避免内存占用过大。
package_length_type 长度值的类型
长度值的类型,接受一个字符参数,与php的pack函数一致。目前swoole支持10种类型:
c:有符号、1字节
C:无符号、1字节
s:有符号、主机字节序、2字节
S:无符号、主机字节序、2字节
n:无符号、网络字节序、2字节 (常用)
N:无符号、网络字节序、4字节 (常用)
l:有符号、主机字节序、4字节(小写L)
L:无符号、主机字节序、4字节(大写L)
v:无符号、小端字节序、2字节
V:无符号、小端字节序、4字节
资料
Last updated