golangはtcp論理粘着パケットとプロトコルフローサイズに対する制約論理を解決する

7196 ワード

tcpデータストリームは受信者のbufサイズが不足している場合、論理的な接着パケットが発生する可能性があり、bufferを使用して接続が完了する前に単一ストリームメッセージを制限する時間が大きいことを確保することができ、手動で[]byteで1つのbufferを実現した.単一の要求では、EOF前のnサイズを読むたびに、しきい値を超えると、アラームが拒否される.この方法は実は愚かで、少なくともナイフのしきい値を読み取る前に、すべて受け入れられる.
実際には、プロトコルが[4]byte全長[4]byteヘッダ長[4]byteヘッダ長[]byteヘッダ長[]byteヘッダ[]byteヘッダ[]byteヘッダ[]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
}