概述

定义

  • Subsystems 是一套可以定义、自动实例化和释放的类的框架。可以将其理解为 GamePlay 级别的 Component
  • 不支持网络赋值
  • 4.22开始引入,4.24完善。(可以移植源码到更早之前的版本使用。源码在手,为所欲为)

五类 Subsystems 及其生命周期

  • UEngineSubsystem(继承自 UDynamicSubsystem,UDynamicSubsystem继承自 USubsystem)

    UEngine* GEngine

    代表引擎,数量1。 Editor或Runtime模式都是全局唯一,从进程启动开始创建,进程退出时销毁。

    UEngine::Init()

  • UEditorSubsystem(继承自 UDynamicSubsystem,UDynamicSubsystem继承自 USubsystem)

    UEditorEngine* GEditor

    代表编辑器,数量1。 顾名思义,只在编辑器下存在且全局唯一,从编辑器启动开始创建,到编辑器退出时销毁。

  • UGameInstanceSubsystem (继承自 USubsystem)

    UGameInstance* GameInstance

    代表一场游戏,数量1。 从游戏的启动开始创建,游戏退出时销毁。这里的一场游戏指的是Runtime或PIE模式的运行的都算,一场游戏里可能会创建多个World切换。

  • UWorldSubsystem (继承自 USubsystem)

    UWorld* World

    代表一个世界,数量可能>1。其生命周期,跟GameMode是一起的。(EWorldType:Game,Editor,PIE,EditorPreview,GamePreview等 )

  • ULocalPlayerSubsystem (继承自 USubsystem)

    ULocalPlayer* LocalPlayer:代表本地玩家,数量可能>1。

    UE支持本地分屏多玩家类型的游戏,但往往最常见的是就只有一个。LocalPlayer虽然往往跟PlayerController一起访问,但是其生命周期其实是跟UGameInstance一起的(默认一开始的时候就创建好一定数量的本地玩家),或者更准确的说是跟LocalPlayer的具体数量挂钩(当然你也可以运行时动态调用AddLocalPlayer)。

为什么要使用 Subsystems

  • 更适用的生命周期

    • 引擎只支持一个 GameInstance ,运行周期是整个引擎的生命周期
    • 自定义 ManagerActor,生命周期一般为当前 level 的生命周期
    • Subsystems 的生命周期可以依存于Engine,Editor,World,LocalPlayer
  • 更简
    • GameInstance 或者自定义 ManagerActor,需要手动维控制创建、释放
    • Subsystems 自动创建、释放,提供 Initialize()、Deinitialize(),并且可重载
  • 更模块化、更优雅、更封装、更易于维护、移植复用
    • GameInstance 中将任务系统,计分系统,经济系统、对话系统等多个Manager 写在一起,会变得臃肿

      • 模块间的数据访问封装不够良好,容易污染
      • 不利于业务逻辑模块的复用,特别是需要进行移植的时候,以及多个插件同时都有自己的 GameInstance
    • Subsystems 可以为不同的 Manager 创建对应的Subsystems
      • 如 Manager 划分,

        • 任务系统Subsystem : UGameInstanceSubsystem
        • 计分系统Subsystem : UGameInstanceSubsystem
        • 经济系统Subsystem : UGameInstanceSubsystem
        • 对话系统Subsystem : UGameInstanceSubsystem
      • 更模块化,代码显得优雅
      • 解耦性高,易于维护、分工协作;易于移植复用
      • 模块间的数据访问具有更好的封装性
  • 更友好的访问接口
    • Subsystem 更像以全局变量的形式来访问
    • 提供了 Python 脚本的访问,用于编写编辑器脚本或编写测试代码
  • Subsystem 无需覆盖引擎类。

Subsystems 的使用

  • 创建过程,涉及 FSubsystemCollectionBase

    FSubsystemCollectionBase::Initialize()
    FSubsystemCollectionBase::AddAndInitializeSubsystem()
    FSubsystemCollectionBase::Deinitialize()

    参考附录源码 或者 EngineDir\Engine\Source\Runtime\Engine\Private\Subsystems\SubsystemCollection.cpp

  • 默认重载函数

    • ShouldCreateSubsystem
    • Initialize()
    • Deinitialize()
  • C++ 访问

    // UMyEngineSubsystem 获取
    UMyEngineSubsystem* MyEngineSubsystem = GEngine->GetEngineSubsystem<UMyEngineSubsystem>(); // UMyEditorSubsystem 获取
    UMyEditorSubsystem* MyEditorSubsystem = GEditor->GetEditorSubsystem<UMyEditorSubsystem>(); // UMyGameInstanceSubsystem 获取
    //UGameInstance* GameInstance = GetWorld()->GetGameInstance();
    UGameInstance* GameInstance = UGameplayStatics::GetGameInstance();
    UMyGameInstanceSubsystem* MyGameInstanceSubsystem = GameInstance->GetSubsystem<UMyGameInstanceSubsystem>(); // UMyWorldSubsystem 获取
    UMyWorldSubsystem* MyWorldSubsystem = GetWorld()->GetSubsystem<UMyWorldSubsystem>(); // UMyLocalPlayerSubsystem 获取
    ULocalPlayer* LocalPlayer = UGameplayStatics::GetPlayerController()->GetLocalPlayer();
    UMyLocalPlayerSubsystem* MyLocalPlayerSubsystem = LocalPlayer->GetSubsystem<UMyLocalPlayerSubsystem>();
    • 引擎自带 USubsystemBlueprintLibrary 访问方法
    UCLASS()
    class ENGINE_API USubsystemBlueprintLibrary : public UBlueprintFunctionLibrary
    {
    GENERATED_BODY() public: /** Get a Game Instance Subsystem from the Game Instance associated with the provided context */
    UFUNCTION(BlueprintPure, Category = "Engine Subsystems", meta = (BlueprintInternalUseOnly = "true"))
    static UEngineSubsystem* GetEngineSubsystem(TSubclassOf<UEngineSubsystem> Class); /** Get a Game Instance Subsystem from the Game Instance associated with the provided context */
    UFUNCTION(BlueprintPure, Category = "GameInstance Subsystems", meta = (WorldContext = "ContextObject", BlueprintInternalUseOnly = "true"))
    static UGameInstanceSubsystem* GetGameInstanceSubsystem(UObject* ContextObject, TSubclassOf<UGameInstanceSubsystem> Class); /** Get a Local Player Subsystem from the Local Player associated with the provided context */
    UFUNCTION(BlueprintPure, Category = "LocalPlayer Subsystems", meta = (WorldContext = "ContextObject", BlueprintInternalUseOnly = "true"))
    static ULocalPlayerSubsystem* GetLocalPlayerSubsystem(UObject* ContextObject, TSubclassOf<ULocalPlayerSubsystem> Class); /** Get a World Subsystem from the World associated with the provided context */
    UFUNCTION(BlueprintPure, Category = "GameInstance Subsystems", meta = (WorldContext = "ContextObject", BlueprintInternalUseOnly = "true"))
    static UWorldSubsystem* GetWorldSubsystem(UObject* ContextObject, TSubclassOf<UWorldSubsystem> Class); /**
    * Get a Local Player Subsystem from the LocalPlayer associated with the provided context
    * If the player controller isn't associated to a LocalPlayer nullptr is returned
    */
    UFUNCTION(BlueprintPure, Category = "LocalPlayer Subsystems", meta = (BlueprintInternalUseOnly = "true"))
    static ULocalPlayerSubsystem* GetLocalPlayerSubSystemFromPlayerController(APlayerController* PlayerController, TSubclassOf<ULocalPlayerSubsystem> Class); private:
    static UWorld* GetWorldFrom(UObject* ContextObject);
    };

UGameInstanceSubsystem

用法一

  • 支持委托

  • 支持普通变量和函数

  • 支持蓝图调用

    UCLASS()
    class DESIGNPATTERNS_API UScoreGameInsSubsystem : public UGameInstanceSubsystem
    {
    GENERATED_BODY()
    public:
    // 是否允许被创建
    virtual bool ShouldCreateSubsystem(UObject* Outer) const override { return true; }
    // 初始化
    virtual void Initialize(FSubsystemCollectionBase& Collection) override;
    // 释放
    virtual void Deinitialize() override; // 声明委托
    DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FScoreChanged, int32, CurrentScore);
    UPROPERTY(BlueprintAssignable)
    FScoreChanged ScoreChange; UFUNCTION(BlueprintCallable, Category = "MySubsystem | ScoreGameInsSubsystem")
    int32 AddScore(int32 BaseScore);
    private:
    int32 Score;
    };
    void UScoreGameInsSubsystem::Initialize(FSubsystemCollectionBase& Collection)
    {
    Super::Initialize(Collection);
    UE_LOG(LogTemp, Warning, TEXT(__FUNCTION__""));
    } void UScoreGameInsSubsystem::Deinitialize()
    {
    Super::Deinitialize();
    UE_LOG(LogTemp, Warning, TEXT(__FUNCTION__""));
    } int32 UScoreGameInsSubsystem::AddScore(int32 BaseScore)
    {
    Score = UKismetMathLibrary::Max(0, Score + BaseScore);
    // 调用委托
    ScoreChange.Broadcast(Score);
    return Score;
    }

用法二

  • 支持创建抽象类,多个派生类,支持蓝图继承,支持遍历访问

    • 注意UCLASS(Type)

      • 父类为 Abstract抽象类,防止实例化
      • Blueprintable 蓝图继承
      • BlueprintType 可定义蓝图变量
    • 注意每种类型的 Subsystem 只能创建一个实例
  • C++访问

    • 访问单个 GetWorld()->GetGameInstance()->GetSubsystem<T>()
    • 访问多个 GetWorld()->GetGameInstance()->GetSubsystemArray<T>()
  • 使用示例

    /**
    * 抽象类 USourceControlSubsystem
    */
    UCLASS(Abstract, Blueprintable, BlueprintType)
    class DESIGNPATTERNS_API USourceControlSubsystem : public UGameInstanceSubsystem
    {
    GENERATED_BODY()
    public:
    // ShouldCreateSubsystem 默认返回 True // 可重载
    UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "MySubsystem | SourceControl")
    FString GetPlatformName();
    }; /**
    * 派生类 UGitSubsystem
    */
    UCLASS()
    class DESIGNPATTERNS_API UGitSubsystem : public USourceControlSubsystem
    {
    GENERATED_BODY()
    public: // 初始化
    virtual void Initialize(FSubsystemCollectionBase& Collection) override {
    Super::Initialize(Collection);
    UE_LOG(LogTemp, Warning, TEXT(__FUNCTION__"【%s】"),*GetName());
    } // 释放
    virtual void Deinitialize() override {
    Super::Deinitialize();
    UE_LOG(LogTemp, Warning, TEXT(__FUNCTION__"【%s】"),*GetName());
    } virtual FString GetPlatformName_Implementation()override {
    UE_LOG(LogTemp, Warning, TEXT(__FUNCTION__"【Git】"));
    return TEXT("Git");
    } void Help() {
    UE_LOG(LogTemp, Warning, TEXT(__FUNCTION__" Help Command"));
    }
    }; /**
    * 派生类 USVNSubsystem
    */
    UCLASS()
    class DESIGNPATTERNS_API USVNSubsystem : public USourceControlSubsystem
    {
    GENERATED_BODY()
    public: // 初始化
    virtual void Initialize(FSubsystemCollectionBase& Collection) override {
    Super::Initialize(Collection);
    UE_LOG(LogTemp, Warning, TEXT(__FUNCTION__"【%s】"), *GetName());
    } // 释放
    virtual void Deinitialize() override {
    Super::Deinitialize();
    UE_LOG(LogTemp, Warning, TEXT(__FUNCTION__"【%s】"), *GetName());
    } virtual FString GetPlatformName_Implementation()override {
    UE_LOG(LogTemp, Warning, TEXT(__FUNCTION__"【SVN】"));
    return TEXT("SVN");
    }
    }; /**
    * 用于测试 ASourceControlActor
    */
    UCLASS(Blueprintable, BlueprintType)
    class DESIGNPATTERNS_API ASourceControlActor : public AActor
    {
    GENERATED_BODY()
    public:
    ASourceControlActor(){} virtual void BeginPlay()override {
    Super::BeginPlay(); // 获取单个 Subsystem
    UGitSubsystem* GitSubsystem = GetWorld()->GetGameInstance()->GetSubsystem<UGitSubsystem>();
    GitSubsystem->Help(); // 获取多个 Subsystem,继承自同个抽象类
    const TArray<USourceControlSubsystem*> SourceControlSubsystems = GetWorld()->GetGameInstance()->GetSubsystemArray<USourceControlSubsystem>();
    UE_LOG(LogTemp, Warning, TEXT(__FUNCTION__"********************* 遍历USourceControlSubsystem ********************"));
    for (USourceControlSubsystem* ItemSubSystem : SourceControlSubsystems)
    {
    ItemSubSystem->GetPlatformName();
    }
    }
    };
  • 蓝图调用

其他用法

  • 支持Tick, 需继承 FTickableGameObject,参考 UAutoDestroySubsystem 写法

    UCLASS()
    class DESIGNPATTERNS_API UScoreGameInsSubsystem : public UGameInstanceSubsystem, public FTickableGameObject
    {
    GENERATED_BODY()
    public: virtual void Tick(float DeltaTime)override{ UE_LOG(LogTemp, Warning, TEXT(__FUNCTION__"Ping Pong"));}
    virtual bool IsTickable()const override { return !IsTemplate(); } //判断是否是 CDO,避免执行两次 Tick
    virtual TStatId GetStatId() const override { RETURN_QUICK_DECLARE_CYCLE_STAT(UMyScoreSubsystem, STATGROUP_Tickables); }
    };
  • 支持 Subsystem 之间的访问

  • 支持多个Subsystem定义依赖顺序,再初始化时调用 Collection.InitializeDependency(UScoreGameInsSubsystem::StaticClass());


UWorldSubsystem

  • 可以再编辑器 和 运行时 使用

    UCLASS()
    class DESIGNPATTERNS_API UMyWorldSubsystem : public UWorldSubsystem
    {
    GENERATED_BODY()
    public:
    // 是否允许被创建
    virtual bool ShouldCreateSubsystem(UObject* Outer) const override { return true; }
    // 初始化
    virtual void Initialize(FSubsystemCollectionBase& Collection) override;
    // 释放
    virtual void Deinitialize() override; FString GetWorldType();
    };
    void UMyWorldSubsystem::Initialize(FSubsystemCollectionBase& Collection)
    {
    UE_LOG(LogTemp, Warning, TEXT(__FUNCTION__" [World] %-20s\t[Type] %s\t"), *GetWorld()->GetName(), *GetWorldType());
    } void UMyWorldSubsystem::Deinitialize()
    {
    UE_LOG(LogTemp, Warning, TEXT(__FUNCTION__" [World] %-20s\t[Type] %s\t"), *GetWorld()->GetName(), *GetWorldType());
    } FString UMyWorldSubsystem::GetWorldType()
    {
    FString WorldTypeName;
    switch (GetWorld()->WorldType) {
    case EWorldType::None: {WorldTypeName = TEXT("None"); }break;
    case EWorldType::Game: {WorldTypeName = TEXT("Game"); }break;
    case EWorldType::Editor: {WorldTypeName = TEXT("Editor"); }break;
    case EWorldType::PIE: {WorldTypeName = TEXT("PIE"); }break;
    case EWorldType::EditorPreview: {WorldTypeName = TEXT("EditorPreview"); }break;
    case EWorldType::GamePreview: {WorldTypeName = TEXT("GamePreview"); }break;
    case EWorldType::GameRPC: {WorldTypeName = TEXT("GameRPC"); }break;
    case EWorldType::Inactive: {WorldTypeName = TEXT("Inactive"); }break;
    default: WorldTypeName = TEXT("default");
    };
    return WorldTypeName;
    }

UEditorSubsystem

  • 需要再 .build.cs 添加 EditorSubsystem 模块

    if (Target.bBuildEditor)
    {
    PublicDependencyModuleNames.AddRange(new string[] { "EditorSubsystem" });
    }
  • 需要添加头文件

  • 编译模式记得选Editor 模式

    #include "EditorSubsystem.h"
    UCLASS()
    class DESIGNPATTERNS_API UMyEditorSubsystem : public UEditorSubsystem
    {
    GENERATED_BODY()
    public: // 是否允许被创建
    virtual bool ShouldCreateSubsystem(UObject* Outer) const override { return true; }
    // 初始化
    virtual void Initialize(FSubsystemCollectionBase& Collection) override;
    // 释放
    virtual void Deinitialize() override; };

系统自带 Subsystem 使用蓝图示例

Asset Editor Subsystem

Asset Tag Subsystem

Editor Utility Subsystem

Layer Subsystem

Import Subsystem

Editor Validator Subsystem

  • 检查、验证资产

  • 从 EditorUtilityBlueprint 中选择父类 EditorValidatorBase


参考


附录

  • SubsystemCollection.cpp

    • FSubsystemCollectionBase::Initialize()
    • FSubsystemCollectionBase::AddAndInitializeSubsystem()
    • FSubsystemCollectionBase::Deinitialize()
    void FSubsystemCollectionBase::Initialize(UObject* NewOuter)
    {
    if (Outer != nullptr)
    {
    // already initialized
    return;
    } Outer = NewOuter;
    check(Outer);
    if (ensure(BaseType) && ensureMsgf(SubsystemMap.Num() == 0, TEXT("Currently don't support repopulation of Subsystem Collections.")))
    {
    check(!bPopulating); //Populating collections on multiple threads? if (SubsystemCollections.Num() == 0)
    {
    FSubsystemModuleWatcher::InitializeModuleWatcher();
    } TGuardValue<bool> PopulatingGuard(bPopulating, true); if (BaseType->IsChildOf(UDynamicSubsystem::StaticClass())) // 判断是否是 UDynamicSubsystem 的子类
    {
    for (const TPair<FName, TArray<TSubclassOf<UDynamicSubsystem>>>& SubsystemClasses : DynamicSystemModuleMap)
    {
    for (const TSubclassOf<UDynamicSubsystem>& SubsystemClass : SubsystemClasses.Value)
    {
    if (SubsystemClass->IsChildOf(BaseType))
    {
    AddAndInitializeSubsystem(SubsystemClass);
    }
    }
    }
    }
    else // 不是 UDynamicSubsystem 的子类
    {
    TArray<UClass*> SubsystemClasses;
    GetDerivedClasses(BaseType, SubsystemClasses, true); for (UClass* SubsystemClass : SubsystemClasses)
    {
    AddAndInitializeSubsystem(SubsystemClass);
    }
    } // Statically track collections
    SubsystemCollections.Add(this);
    }
    } void FSubsystemCollectionBase::Deinitialize()
    {
    // Remove static tracking
    SubsystemCollections.Remove(this);
    if (SubsystemCollections.Num() == 0)
    {
    FSubsystemModuleWatcher::DeinitializeModuleWatcher();
    } // Deinit and clean up existing systems
    SubsystemArrayMap.Empty();
    for (auto Iter = SubsystemMap.CreateIterator(); Iter; ++Iter) // 遍历 SubsystemMap
    {
    UClass* KeyClass = Iter.Key();
    USubsystem* Subsystem = Iter.Value();
    if (Subsystem->GetClass() == KeyClass)
    {
    Subsystem->Deinitialize(); // 清理、释放
    Subsystem->InternalOwningSubsystem = nullptr;
    }
    }
    SubsystemMap.Empty();
    Outer = nullptr;
    } USubsystem* FSubsystemCollectionBase::AddAndInitializeSubsystem(UClass* SubsystemClass)
    {
    if (!SubsystemMap.Contains(SubsystemClass))
    {
    // Only add instances for non abstract Subsystems
    if (SubsystemClass && !SubsystemClass->HasAllClassFlags(CLASS_Abstract))
    {
    // Catch any attempt to add a subsystem of the wrong type
    checkf(SubsystemClass->IsChildOf(BaseType), TEXT("ClassType (%s) must be a subclass of BaseType(%s)."), *SubsystemClass->GetName(), *BaseType->GetName()); // Do not create instances of classes aren't authoritative
    if (SubsystemClass->GetAuthoritativeClass() != SubsystemClass)
    {
    return nullptr;
    } const USubsystem* CDO = SubsystemClass->GetDefaultObject<USubsystem>();
    if (CDO->ShouldCreateSubsystem(Outer)) // 从CDO调用ShouldCreateSubsystem来判断是否要创建
    {
    USubsystem* Subsystem = NewObject<USubsystem>(Outer, SubsystemClass); //创建
    SubsystemMap.Add(SubsystemClass,Subsystem); // 添加到 SubsystemMap
    Subsystem->InternalOwningSubsystem = this;
    Subsystem->Initialize(*this); //调用Initialize
    return Subsystem;
    }
    }
    return nullptr;
    } return SubsystemMap.FindRef(SubsystemClass);
    }

【UE4 C++】编程子系统 Subsystem的更多相关文章

  1. Windows - 子系统(subsystem)错误

    Windows - 子系统(subsystem)错误 本文地址: http://blog.csdn.net/caroline_wendy VS2012生成错误: "error LNK2019 ...

  2. UE4蓝图编程的第一步

    认识UE4蓝图中颜色与变量类型: UE4中各个颜色对应着不同的变量,连接点和连线的颜色都在表示此处是什么类型的变量.对于初学者来说一开始看到那么多连接点, 可能会很茫然,搞不清还怎么连,如果知道了颜色 ...

  3. UE4的编程C++创建一个FPSproject(两)角色网格、动画、HUD、子弹类

    立即归还,本文将总结所有这些整理UE4有关角色的网络格.动画.子弹类HUD一个简单的实现. (五)角色加入网格 Character类为我们默认创建了一个SkeletaMeshComponent组件,所 ...

  4. UE4新手编程之创建C++项目

    虚幻4中常用的按键和快捷键 虚幻4中有一些按键和快捷键很常用,牢记它们并运动到实际的项目开发中,将会大大地提高你的工作效率和使得工作更简便快捷.下面将列举它们出来: 按键   动作  鼠标左键   选 ...

  5. UE4新手编程之创建空白关卡和添加碰撞体

    让我们接着上次继续学习UE4引擎,今天我们学习下怎样创建空白的关卡以及添加碰撞物体. 一. 创建空白关卡 1) 点击文件 -> 新建关卡(或者按快捷键Ctrl+N). 2) 你可以选择Defau ...

  6. ue4 C++ 编程 通过三个点的位置算出夹角

    const FVector2D& Pt1 = 第一个点的位置; const FVector2D& Pt2 = 第二个点的位置; float EdgeRadians1 = FMath:: ...

  7. 【UE4 C++】学习笔记汇总

    UE4 概念知识 基础概念--文件结构.类型.反射.编译.接口.垃圾回收.序列化[导图] GamePlay架构[导图] 类的继承层级关系[导图] 反射机制 垃圾回收机制/算法 序列化 Actor 的生 ...

  8. 【UE4】GamePlay架构

    新标签打开或者下载看大图 更新: 增加 编程子系统 Subsystem 思维导图 Character pipeline

  9. UE4编程之C++创建一个FPS工程(一)创建模式&角色&处理输入

    转自:http://blog.csdn.net/u011707076/article/details/44180951 从今天开始,我们一起来学习一下,如何使用C++将一个不带有任何初学者内容的空模板 ...

随机推荐

  1. Spring Boot 入门系列(二十四)多环境配置,3分钟搞定!

    之前讲过Spring Boot 的系统配置和自定义配置,实现了按照实际项目的要求配置系统的相关熟悉.但是,在实际项目开发过程中,需要面对不同的环境,例如:开发环境,测试环境,生产环境.各个环境的数据库 ...

  2. 被面试官问懵:TCP 四次挥手收到乱序的 FIN 包会如何处理?

    摘要:收到个读者的问题,他在面试的时候,被搞懵了,因为面试官问了他这么一个网络问题. 本文分享自华为云社区<TCP 四次挥手收到乱序的 FIN 包会如何处理?>,作者:小林coding . ...

  3. python模块--__future__(向上兼容模块)

    py2.7   unicode_literals 将字符串默认视为unicode, 即u'xxx'和'xxx'将是一样的, 而再想表示字节需用b'xxx'表示 division / 将表示正常除法操作 ...

  4. CodeForce-792C Divide by Three(数学)

    Divide by Three CodeForces - 792C 有一个正整数 n 写在黑板上.它有不超过 105 位. 你需要通过删除一些位使得他变成一个美丽的数,并且需要删除尽量少的位数.删除的 ...

  5. Mixed Content: The page at 'xxx' was loaded over HTTPS, but requested an insecure resource 'xxx'.

    HTTPS页面里动态的引入HTTP资源,比如引入一个js文件,会被直接block掉的.在HTTPS页面里通过AJAX的方式请求HTTP资源,也会被直接block掉的. Mixed Content: T ...

  6. php 开启报错

    // 开启报错提醒ini_set("display_errors", "On");error_reporting(E_ALL | E_STRICT); // 某 ...

  7. CentOS7安装Docker遇到的问题笔记

    笔记/朱季谦 以下是笔者本人学习搭建docker过程当中记录的一些实践笔记,过程当中也遇到了一些坑,但都解决了,就此记录,留作以后再次搭建时可以直接参考. 一.首先,先检查CentOS版本,保证在Ce ...

  8. Kubernetes-Pod介绍(四)-Deployment

    前言 本篇是Kubernetes第七篇,大家一定要把环境搭建起来,看是解决不了问题的,必须实战. Kubernetes系列文章: Kubernetes介绍 Kubernetes环境搭建 Kuberne ...

  9. 为什么Charles中的中文展示成数字、英文字符串

    在使用charles抓包时,可能非看到如下图的字符串: 为什么会出现这样的字符串? 我们看到的汉字.字母,对电脑来说并不长这样,而是用二进制表示的(显然--),为了统一标准,老外发明了"字符 ...

  10. 查看Docker启动jenkins的管理员密码

    Docker启动docker后,第一次方法jenkins,需要输入管理员密码. 其实查看启动时候的日志可以看到密码,也可以按照以下方法找到密码. 1.查看docker容器ID:docker ps -a ...