什么是粘包问题
发送方发送的若干包数据到接收方时粘成一包,从接受缓冲区来看就是后一包数据的头紧接着前一包数据的尾。
粘包出现的原因
发送方等待到缓冲区满才将包发送出去
若连续几次发送数据都很小,tcp会根据优化算法把这些数据整合成一包后一次性发送,这样接收方就收到了粘包数据。
接收方不及时接受缓冲区的包,造成多个包接收
接收方会先把收到的数据放在系统接收缓冲区,用户进程从该缓冲区读取数据,若下一包数据到达时前一包数据尚未被用户进程取走,则下一包数据进入缓冲区时就到前一包数据之后,而用户进程根据预先设定的缓冲区大小从系统中读取数据,这样便一次取了很多包。
解决方法--封包和解包
发送方在发送数据的包前,加入数据长度,将数据包的结构变成[dataLen|data]的结构再进行发送。而接收方通过解析这种结构,从而将多个数据包聚合形成的粘包分解成一个个独立的数据包。具体核心代码如下所示:
发送方封包:
const (
DataLen = 4
)
//封装数据包
func Packet(message []byte) []byte {
return append(IntToBytes(len(message)), message...)
}
接收方解包:
const (
DataLen = 4
)
//解包
func Unpack(buffer []byte, readerChannel chan []byte) []byte {
length := len(buffer)
var i int
for i = 0; i < length; i++ {
if length < i + DataLen {
break
}
//根据长度来获取数据
messageLen := BytesToInt(buffer[i:i+DataLen])
if length < i + DataLen + messageLen {
break
}
data := buffer[i+DataLen:i+DataLen+messageLen]
readerChannel <- data
i += DataLen + messageLen - 1
}
if i == length {
return make([]byte, 0)
}
return buffer[i:]
}