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
}