粘包问题

网络协议为计算机网络中进行交互而建立的规则,标准或约定的集合

socket 通讯

socket屏蔽了底层通讯的机制

为了数据高效传输

协议分层

tcp/ip 协议族是一个四层协议系统,自底而上分别是数据链路层,网络层、传输层和应用层

应用层  ping  telnet OSPF DNS

要有应答,

收发有缓冲区

3.1什么是 TCP 粘包?

TCP 粘包是指发送方发送的若干包数据 到 接收方接收时粘成一包,从接收缓冲区看,后一包数据的头紧接着前一包数据的尾。

TCP通信特点

  1. TCP 是流式协议没有消息边界,客户端向服务器端发送一次数据,可能会被服务器端分成多次收到。客户端向服务器端发送多条数据。服务器端可能一次全部收到。

2.保证传输的可靠性,顺序。

3.TCP拥有拥塞控制,所以数据包可能会延后发送。

 

没有消息边界:

可以理解为水在一个水管里的流动,我们不知道哪段数据是一个我们需要的完整数据

 

收发有缓冲区:

比如:当水从一端流到了另一端,我们在收数据的时候,不可能每来一滴水就处理一次,这个缓冲区就相当于有了一个水桶,再接了一定的水之后内核再给数据交到用户空间,

3.3 Swoole怎么处理粘包

3.3.1、EOF 结束协议

通过约定结束符,来确定包数据是否发送完毕

开启open_eof_check=true,并用package_eof来设置一个完整数据结尾字符,同时设置自动拆分open_eof_split

 

注意:

  • 要保证业务数据里不能出现package_eof设置的字符,否则将导致数据错误了。

2、可以手动拆包,去掉open_eof_split,自行 explode(“\r\n”, $data),然后循环发送

3.3.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字节

服务端A既是客户端也是服务器,服务端A要发送请求到服务端B,然后服务端B返回消息给服务端A

 

 

发表评论

电子邮件地址不会被公开。 必填项已用*标注