tcp数据流在接收方的buf大小不足时,可能会出现逻辑粘包,可以使用buffer确保接完
以前在限制单条流消息大小时,是手动用[]byte实现了一个buffer,单条请求里,每次读到EOF前的n大小,一超过阈值,就报警拒绝,这个做法其实很蠢,至少会在读取刀阈值以前,全接受。

实际上更好的逻辑是,用指定长度的[]byte去读取一些定长的头部信息
比如假设协议是:
[4]byte 总长度
[4]byte 头部长度
[4]byte body长度
[]byte 头部
[]byte body

那么,与其读取过程中去动态判读是否超值,更好的方法是用[4]byte 接受总长度
如果 总长度的值 >阈值,直接报警拒绝,则该逻辑对非法请求最多就是读取12位,而不是读到阈值大小。

一般总长度是不包括自身的[4]byte的,所以严格逻辑是 总长度的值>阈值+4,但是这种限制是弱一致的,不碍事!

具体的实现如下:

func UnpackToBlockFromReader(reader io.Reader, maxLength int32) ([]byte, error) {
if reader == nil {
return nil, errors.New("reader is nil")
}
var info = make([]byte, 4, 4)
n, e := reader.Read(info)
if e != nil {
return nil, e
}

if n != 4 {
return nil, errors.New("can't read 4 length info block from reader, but read " + strconv.Itoa(n))
}
length:= binary.BigEndian.Uint32(info[0:4])
if length >= maxLength {
return info, errors.New(fmt.Sprintf("beyond max size limit %d but got %d", maxLength, length))
}
var content = make([]byte, length, length)
n, e = reader.Read(content)
if e != nil {
return nil, e
}
if n != int(length) {
return nil, errors.New(fmt.Sprintf("can't read %d length content block from reader, but read %d", length, n))
}

return append(info, content ...), nil
}