code: func (p *MsgParser) Read(conn *TCPConn) ([]byte, error) {
  	var b [4]byte
  	bufMsgLen := b[:p.lenMsgLen]
  
  	// read len
  	if _, err := io.ReadFull(conn, bufMsgLen); err != nil {
  		return nil, err
  	}
  
  	// parse len
  	var msgLen uint32
  	switch p.lenMsgLen {
  	case 1:
  		msgLen = uint32(bufMsgLen[0])
  	case 2:
  		if p.littleEndian {
  			msgLen = uint32(binary.LittleEndian.Uint16(bufMsgLen))
  		} else {
  			msgLen = uint32(binary.BigEndian.Uint16(bufMsgLen))
  		}
  	case 4:
  		if p.littleEndian {
  			msgLen = binary.LittleEndian.Uint32(bufMsgLen)
  		} else {
  			msgLen = binary.BigEndian.Uint32(bufMsgLen)
  		}
  	}
  
  	// check len
  	if msgLen > p.maxMsgLen {
  		return nil, errors.New("message too long")
  	} else if msgLen < p.minMsgLen {
  		return nil, errors.New("message too short")
  	}
  
  	// data
  	msgData := make([]byte, msgLen)
  	if _, err := io.ReadFull(conn, msgData); err != nil {
  		return nil, err
  	}
  
  	return msgData, nil
  }
docs: // goroutine safe