文章目录

  • 1、Dart 当中的 「…」表示什么意思?
  • 2、Dart 的作用域
  • 3、Dart 是不是单线程模型?是如何运行的?
  • 4、 说一下 Future?
  • 5、说一下 Stream?
  • 6、说一下 mixin?
  • 7、StatefulWidget 的生命周期
  • 8、 Flutter 如何与 Android iOS 通信?
  • 9、dart是什么,和flutter有什么关系?
  • 10、main()和runApp()函数在flutter的作用分别是什么?有什么关系吗?
  • 11、什么是widget? 在flutter里有几种类型的widget?分别有什么区别?能分别说一下生命周期吗?
  • 12、Hot Restart 和 Hot Reload 有什么区别吗?
  • 13、在flutter里streams是什么?有几种streams?有什么场景用到它?
  • 14、简单说一下在flutter里async和await?
  • 15、future 和steam有什么不一样?
  • 16、什么是flutter里的key? 有什么用?
  • 17、在什么场景下使用profile mode?
  • 18、怎么做到只在debug mode运行代码?
  • 19、怎么理解Isolate?
  • 20、await for 如何使用?
  • 21、请简单介绍下Flutter框架,以及它的优缺点?
  • 22、介绍下Flutter的理念架构
  • 23、介绍下FFlutter的FrameWork层和Engine层,以及它们的作用
  • *24、介绍下Widget、State、Context 概念
  • *25、简述Widgets、RenderObjects 和 Elements的关系
  • 26、简述Flutter的绘制流程
  • 27、Dart中var与dynamic的区别
  • 28、const和final的区别
  • 29、Dart中??与??=的区别
  • *30、Widget、Element、RenderObject三者之间的关系
  • 31、Flutter在Debug和Release下分别使用什么编译模式,有什么区别?
  • 32、Flutter 是什么?
  • 33、Flutter 特性有哪些?
  • 34、Flutter 和 Dart的关系是什么?
  • 35、dart的一些重要概念?
  • 36、dart是值传递还是引用传递?
  • 37、 mixin extends implement 之间的关系?
  • 38、Flutter main future mirotask 的执行顺序?
  • 39、Future和Isolate有什么区别?
  • 40、Stream 两种订阅模式?
  • 41、Flutter state生命周期方法之didChangeDependencies 、didUpdateWidget
  • 42、flutter key的种类

1、Dart 当中的 「…」表示什么意思?

Dart 当中的 「…」意思是 「级联操作符」,为了方便配置而使用。

「…」和「.」不同的是 调用「…」后返回的相当于是 this,而「.」返回的则是该方法返回的值 。

2、Dart 的作用域

Dart 没有 「public」「private」等关键字,默认就是公开的,私有变量使用 下划线 _开头。

3、Dart 是不是单线程模型?是如何运行的?

Dart 是单线程模型,如何运行的看这张图:

引用《Flutter中文网》里的话:

Dart 在单线程中是以消息循环机制来运行的,其中包含两个任务队列,一个是“微任务队列” microtask queue,另一个叫做“事件队列” event queue。

入口函数 main() 执行完后,消息循环机制便启动了。首先会按照先进先出的顺序逐个执行微任务队列中的任务,当所有微任务队列执行完后便开始执行事件队列中的任务,事件任务执行完毕后再去执行微任务,如此循环往复,生生不息。

4、 说一下 Future?

Future,字面意思「未来」,是用来处理异步的工具。

刚才也说过:

Dart 在单线程中是以消息循环机制来运行的,其中包含两个任务队列,一个是“微任务队列” microtask queue,另一个叫做“事件队列” event queue。

Future 默认情况下其实就是往「事件队列」里插入一个事件,当有空余时间的时候就去执行,当执行完毕后会回调 Future.then(v) 方法。

而我们也可以通过使用 Future.microtask 方法来向 「微任务队列」中插入一个任务,这样就会提高他执行的效率。

因为在 Dart 每一个 isolate 当中,执行优先级为 : Main > MicroTask > EventQueue

5、说一下 Stream?

Stream 和 Feature 一样,都是用来处理异步的工具。

但是 Stream 和 Feature 不同的地方是 Stream 可以接收多个异步结果,而Feature 只有一个。

Stream 的创建可以使用 Stream.fromFuture,也可以使用 StreamController 来创建和控制。

还有一个注意点是:普通的 Stream 只可以有一个订阅者,如果想要多订阅的话,要使用 asBroadcastStream()。

6、说一下 mixin?

首先mixin是一个定义类的关键字。直译出来是混入,混合的意思 Dart为了支持多重继承,引入了mixin关键字,它最大的特殊处在于: mixin定义的类不能有构造方法,这样可以避免继承多个类而产生的父类构造方法冲突。

7、StatefulWidget 的生命周期

  • initState():Widget 初始化当前 State,在当前方法中是不能获取到 Context 的,如想获取,可以试试 Future.delayed()
  • didChangeDependencies():在 initState() 后调用,State对象依赖关系发生变化的时候也会调用。
  • deactivate():当 State 被暂时从视图树中移除时会调用这个方法,页面切换时也会调用该方法,和Android里的 onPause 差不多。
  • dispose():Widget 销毁时调用。
  • didUpdateWidget:Widget 状态发生变化的时候调用。

8、 Flutter 如何与 Android iOS 通信?

Flutter 通过 PlatformChannel 与原生进行交互,其中 PlatformChannel 分为三种:

  • BasicMessageChannel:用于传递字符串和半结构化的信息。
  • MethodChannel:用于传递方法调用。Flutter主动调用Native的方法,并获取相应的返回值。
  • EventChannel:用于数据流(event streams)的通信。

9、dart是什么,和flutter有什么关系?

dart是一种面向对象语言,dart是flutter的程序开发语言。

10、main()和runApp()函数在flutter的作用分别是什么?有什么关系吗?

  • main函数是类似于java语言的程序运行入口函数
  • runApp函数是渲染根widget树的函数
  • 一般情况下runApp函数会在main函数里执行

11、什么是widget? 在flutter里有几种类型的widget?分别有什么区别?能分别说一下生命周期吗?

widget在flutter里基本是一些UI组件有两种类型的widget,分别是statefulWidget 和 statelessWidget两种,statelessWidget不会自己重新构建自己,但是statefulWidget会

12、Hot Restart 和 Hot Reload 有什么区别吗?

Hot Reload比Hot Restart快,Hot Reload会编译我们文件里新加的代码并发送给dart虚拟机,dart会更新widgets来改变UI,而Hot Restart会让dart 虚拟机重新编译应用。另一方面也是因为这样, Hot Reload会保留之前的state,而Hot Restart回你重置所有的state回到初始值。

13、在flutter里streams是什么?有几种streams?有什么场景用到它?

Stream 用来处理连续的异步操作,Stream 是一个抽象类,用于表示一序列异步数据的源。它是一种产生连续事件的方式,可以生成数据事件或者错误事件,以及流结束时的完成事件

Stream 分单订阅流和广播流。

网络状态的监控

14、简单说一下在flutter里async和await?

await的出现会把await之前和之后的代码分为两部分,await并不像字面意思所表示的程序运行到这里就阻塞了,而是立刻结束当前函数的执行并返回一个Future,函数内剩余代码通过调度异步执行。

async是和await搭配使用的,await只在async函数中出现。在async 函数里可以没有await或者有多个await。

15、future 和steam有什么不一样?

在 Flutter 中有两种处理异步操作的方式 Future 和 Stream,Future 用于处理单个异步操作,Stream 用来处理连续的异步操作。

16、什么是flutter里的key? 有什么用?

key是Widgets,Elements和SemanticsNodes的标识符。

key有LocalKey 和 GlobalKey两种。

LocalKey 如果要修改集合中的控件的顺序或数量。GlobalKey允许 Widget 在应用中的任何位置更改父级而不会丢失 State。

17、在什么场景下使用profile mode?

profile model 是用来评估app性能的,profile model 和release mode是相似的,只有保留了一些需要评估app性能的debug功能。在模拟器上profile model是不可用的。

18、怎么做到只在debug mode运行代码?

foundation有一个静态的变量kReleaseMode来表示是否是release mode。

19、怎么理解Isolate?

isolate是Dart对actor并发模式的实现。 isolate是有自己的内存和单线程控制的运行实体。isolate本身的意思是“隔离”,因为isolate之间的内存在逻辑上是隔离的。isolate中的代码是按顺序执行的,任何Dart程序的并发都是运行多个isolate的结果。因为Dart没有共享内存的并发,没有竞争的可能性所以不需要锁,也就不用担心死锁的问题。

20、await for 如何使用?

await for是不断获取stream流中的数据,然后执行循环体中的操作。它一般用在直到stream什么时候完成,并且必须等待传递完成之后才能使用,不然就会一直阻塞。

21、请简单介绍下Flutter框架,以及它的优缺点?

Flutter是Google推出的一套开源跨平台UI框架,可以快速地在Android、iOS和Web平台上构建高质量的原生用户界面。同时,Flutter还是Google新研发的Fuchsia操作系统的默认开发套件。在全世界,Flutter正在被越来越多的开发者和组织使用,并且Flutter是完全免费、开源的。Flutter采用现代响应式框架构建,其中心思想是使用组件来构建应用的UI。当组件的状态发生改变时,组件会重构它的描述,Flutter会对比之前的描述,以确定底层渲染树从当前状态转换到下一个状态所需要的最小更改。

优点

  • 热重载(Hot Reload),利用Android Studio直接一个ctrl+s就可以保存并重载,模拟器立马就可以看见效果,相比原生冗长的编译过程强很多;
  • 一切皆为Widget的理念,对于Flutter来说,手机应用里的所有东西都是Widget,通过可组合的空间集合、丰富的动画库以及分层课扩展的架构实现了富有感染力的灵活界面设计;
  • 借助可移植的GPU加速的渲染引擎以及高性能本地代码运行时以达到跨平台设备的高质量用户体验。简单来说就是:最终结果就是利用Flutter构建的应用在运行效率上会和原生应用差不多。

缺点

  • 不支持热更新;
  • 三方库有限,需要自己造轮子;
  • Dart语言编写,增加了学习难度,并且学习了Dart之后无其他用处,相比JS和Java来说。

22、介绍下Flutter的理念架构

由上图可知,Flutter框架自下而上分为Embedder、Engine和Framework三层。其中,Embedder是操作系统适配层,实现了渲染 Surface设置,线程设置,以及平台插件等平台相关特性的适配;Engine层负责图形绘制、文字排版和提供Dart运行时,Engine层具有独立虚拟机,正是由于它的存在,Flutter程序才能运行在不同的平台上,实现跨平台运行;Framework层则是使用Dart编写的一套基础视图库,包含了动画、图形绘制和手势识别等功能,是使用频率最高的一层。

23、介绍下FFlutter的FrameWork层和Engine层,以及它们的作用

Flutter的FrameWork层是用Drat编写的框架(SDK),它实现了一套基础库,包含Material(Android风格UI)和Cupertino(iOS风格)的UI界面,下面是通用的Widgets(组件),之后是一些动画、绘制、渲染、手势库等。这个纯 Dart实现的 SDK被封装为了一个叫作 dart:ui的 Dart库。我们在使用 Flutter写 App的时候,直接导入这个库即可使用组件等功能。

Flutter的Engine层是Skia 2D的绘图引擎库,其前身是一个向量绘图软件,Chrome和 Android均采用 Skia作为绘图引擎。Skia提供了非常友好的 API,并且在图形转换、文字渲染、位图渲染方面都提供了友好、高效的表现。Skia是跨平台的,所以可以被嵌入到 Flutter的 iOS SDK中,而不用去研究 iOS闭源的 Core Graphics / Core Animation。Android自带了 Skia,所以 Flutter Android SDK要比 iOS SDK小很多。

*24、介绍下Widget、State、Context 概念

  • Widget:在Flutter中,几乎所有东西都是Widget。将一个Widget想象为一个可视化的组件(或与应用可视化方面交互的组件),当你需要构建与布局直接或间接相关的任何内容时,你正在使用Widget。
  • Widget树:Widget以树结构进行组织。包含其他Widget的widget被称为父Widget(或widget容器)。包含在父widget中的widget被称为子Widget。
  • Context:仅仅是已创建的所有Widget树结构中的某个Widget的位置引用。简而言之,将context作为widget树的一部分,其中context所对应的widget被添加到此树中。一个context只从属于一个widget,它和widget一样是链接在一起的,并且会形成一个context树。
  • State:定义了StatefulWidget实例的行为,它包含了用于”交互/干预“Widget信息的行为和布局。应用于State的任何更改都会强制重建Widget。

*25、简述Widgets、RenderObjects 和 Elements的关系

首先看一下这几个对象的含义及作用。

Widget :仅用于存储渲染所需要的信息。
RenderObject :负责管理布局、绘制等操作。
Element :才是这颗巨大的控件树上的实体。

Widget会被inflate(填充)到Element,并由Element管理底层渲染树。Widget并不会直接管理状态及渲染,而是通过State这个对象来管理状态。Flutter创建Element的可见树,相对于Widget来说,是可变的,通常界面开发中,我们不用直接操作Element,而是由框架层实现内部逻辑。就如一个UI视图树中,可能包含有多个TextWidget(Widget被使用多次),但是放在内部视图树的视角,这些TextWidget都是填充到一个个独立的Element中。Element会持有renderObject和widget的实例。记住,Widget 只是一个配置,RenderObject 负责管理布局、绘制等操作。

在第一次创建 Widget 的时候,会对应创建一个 Element, 然后将该元素插入树中。如果之后 Widget 发生了变化,则将其与旧的 Widget 进行比较,并且相应地更新 Element。重要的是,Element 不会被重建,只是更新而已。

26、简述Flutter的绘制流程

Flutter只关心向 GPU提供视图数据,GPU的 VSync信号同步到 UI线程,UI线程使用 Dart来构建抽象的视图结构,这份数据结构在 GPU线程进行图层合成,视图数据提供给 Skia引擎渲染为 GPU数据,这些数据通过 OpenGL或者 Vulkan提供给 GPU。

27、Dart中var与dynamic的区别

使用var来声明变量,dart会在编译阶段自动推导出类型。而dynamic不在编译期间做类型检查而是在运行期间做类型校验。

28、const和final的区别

const 的值在编译期确定,final 的值在运⾏时确定。

29、Dart中??与??=的区别

两者都是dart中的操作符,??表示如果为空则返回,??=表示如果为空则赋值。

*30、Widget、Element、RenderObject三者之间的关系

  • Widget是用户界面的一部分,并且是不可变的。
  • Element是在树中特定位置Widget的实例。
  • RenderObject是渲染树中的一个对象,它的层次结构是渲染库的核心。

Widget会被inflate(填充)到Element,并由Element管理底层渲染树。Widget并不会直接管理状态及渲染,而是通过State这个对象来管理状态。Flutter创建Element的可见树,相对于Widget来说,是可变的,通常界面开发中,我们不用直接操作Element,而是由框架层实现内部逻辑。就如一个UI视图树中,可能包含有多个TextWidget(Widget被使用多次),但是放在内部视图树的视角,这些TextWidget都是填充到一个个独立的Element中。Element会持有renderObject和widget的实例。记住,Widget 只是一个配置,RenderObject 负责管理布局、绘制等操作。

在第一次创建 Widget 的时候,会对应创建一个 Element, 然后将该元素插入树中。如果之后 Widget 发生了变化,则将其与旧的 Widget 进行比较,并且相应地更新 Element。重要的是,Element 不会被重建,只是更新而已。

31、Flutter在Debug和Release下分别使用什么编译模式,有什么区别?

Debug模式下使用JIT编译模式,即Just in time(即时编译),Release下使用AOT模式,即Ahead of time(提前编译)。JIT模式因为需要边运行边编译,所以会占用运行时内存,导致卡顿现象,但是有动态编译效果对于开发者来说非常方便调试。AOT模式提前编译不会占用运行时内存,相对来说运行流畅,但是会导致编译时间增加。

32、Flutter 是什么?

Flutter是谷歌的移动UI框架,可以快速在iOS和Android上构建高质量的原生用户界面。 Flutter可以与现有的代码一起工作。在全世界,Flutter正在被越来越多的开发者和组织使用,并且Flutter是完全免费、开源的。

33、Flutter 特性有哪些?

  • 快速开发(毫秒级热重载)
  • 绚丽UI(内建漂亮的质感设计Material Design和Cupertino Widget和丰富平滑的动画效果和平台感知)
  • 响应式(Reactive,用强大而灵活的API解决2D、动画、手势、效果等难题)
  • 原生访问功能
  • 堪比原生性能

34、Flutter 和 Dart的关系是什么?

Flutter是一个使用Dart语言开发的跨平台移动UI框架,通过自建绘制引擎,能高性能、高保真地进行移动开发。Dart囊括了多数编程语言的优点,它更符合Flutter构建界面的方式。

35、dart的一些重要概念?

  • 在Dart中,一切都是对象,所有的对象都是继承自Object
  • Dart是强类型语言,但可以用var或 dynamic来声明一个变量,Dart会自动推断其数据类型,dynamic类似c#
  • 没有赋初值的变量都会有默认值null
  • Dart支持顶层方法,如main方法,可以在方法内部创建方法
  • Dart支持顶层变量,也支持类变量或对象变量
  • Dart没有public protected private等关键字,如果某个变量以下划线(_)开头,代表这个变量在库中是私有的

36、dart是值传递还是引用传递?

dart中,基本数据类型传值,类传引用。

37、 mixin extends implement 之间的关系?

继承(关键字 extends)、混入 mixins (关键字 with)、接口实现(关键字 implements)。这三者可以同时存在,前后顺序是extends -> mixins -> implements。

Flutter中的继承是单继承,子类重写超类的方法要用@Override,子类调用超类的方法要用super。

在Flutter中,Mixins是一种在多个类层次结构中复用类代码的方法。mixins的对象是类,mixins绝不是继承,也不是接口,而是一种全新的特性,可以mixins多个类,mixins的使用需要满足一定条件。

38、Flutter main future mirotask 的执行顺序?

普通代码都是同步执行的,结束后会开始检查microtask中是否有任务,若有则执行,执行完继续检查microtask,直到microtask列队为空。最后会去执行event队列(future)。

39、Future和Isolate有什么区别?

future是异步编程,调用本身立即返回,并在稍后的某个时候执行完成时再获得返回结果。在普通代码中可以使用await 等待一个异步调用结束。

isolate是并发编程,Dartm有并发时的共享状态,所有Dart代码都在isolate中运行,包括最初的main()。每个isolate都有它自己的堆内存,意味着其中所有内存数据,包括全局数据,都仅对该isolate可见,它们之间的通信只能通过传递消息的机制完成,消息则通过端口(port)收发。isolate只是一个概念,具体取决于如何实现,比如在Dart VM中一个isolate可能会是一个线程,在Web中可能会是一个Web Worker。

40、Stream 两种订阅模式?

Stream有两种订阅模式:单订阅(single) 和 多订阅(broadcast)。单订阅就是只能有一个订阅者,而广播是可以有多个订阅者。这就有点类似于消息服务(Message Service)的处理模式。单订阅类似于点对点,在订阅者出现之前会持有数据,在订阅者出现之后就才转交给它。而广播类似于发布订阅模式,可以同时有多个订阅者,当有数据时就会传递给所有的订阅者,而不管当前是否已有订阅者存在。

Stream 默认处于单订阅模式,所以同一个 stream 上的 listen 和其它大多数方法只能调用一次,调用第二次就会报错。但 Stream 可以通过 transform() 方法(返回另一个 Stream)进行连续调用。通过 Stream.asBroadcastStream() 可以将一个单订阅模式的 Stream 转换成一个多订阅模式的 Stream,isBroadcast 属性可以判断当前 Stream 所处的模式。

41、Flutter state生命周期方法之didChangeDependencies 、didUpdateWidget

  • didChangeDependencies
    widget树中,若节点的父级结构中的层级 或 父级结构中的任一节点的widget类型有变化,节点会调用didChangeDependencies;若仅仅是父级结构某一节点的widget的某些属性值变化,节点不会调用didChangeDependencies

  • didUpdateWidget
    widget树中,若节点调用setState方法,节点本身不会触发didUpdateWidget,此节点的子节点 会 调用didUpdateWidget

42、flutter key的种类

  • GlobalKey

Globalkey可以主动获取以及主动改变子控件的状态。

  • LocalKey

ValueKey
ObjectKey
UniqueKey

flutter面试题相关推荐

  1. Flutter面试题——面试题1

    一 面试题知识点 Flutter种Widget视图的生命周期 Flutter中的三棵树 Flutter动画 Flutter中手势操作 Flutter绘制(签名/画笔) 有无做过手绘相关的项目 Flut ...

  2. Android面试中多说这么一句话,薪水直接涨5k,flutter面试题2021

    在回答HR提出的薪资问题时,往往同学们都倾向于一个固定数字,比如说10K.那么恭喜你!你已经被HR成功套路!遇到这种情况,如果你去直接报价,如果报低了,那HR做梦都会笑醒. 如果没有报低,HR也会顺着 ...

  3. 0基础学android开发,我们究竟还要学习哪些Android知识

    前言 如果你也学习Android,那么你大概率会看过我的文章.经常有读者给我留言:"该怎么学习Android?"."日常学习Android的方法是什么". 所以 ...

  4. Flutter 初尝:从 Java 无缝过渡,java开发面试笔试题

    我总结出了很多互联网公司的面试题及答案,并整理成了文档,以及各种学习的进阶学习资料,免费分享给大家. 扫描二维码加VX好友,拉你进[程序员面试学习交流群]免费领取.也欢迎各位一起在群里探讨技术. 准备 ...

  5. flutter 真机无法调试 sdk报错_老许,你要转Flutter不要?只要你开金口,面试题现在就给你送来...

    概述 Flutter是Google推出的一套开源跨平台UI框架,可以快速地在Android.iOS和Web平台上构建高质量的原生用户界面.在过去的一年里,Flutter的更新频率是相当的快,也有很多的 ...

  6. flutter开发视频播放器,69个经典安卓面试题和答案详解,下载量瞬秒百万

    这篇文章最近很火,我也有一些自己的看法:现在去很多公司面试,除了你具备基本的能够写一个高性能app的能力后,一般都会在自己的app里面加一些现有的相对较666的技术,这些技术我们称之为开源框架. 比如 ...

  7. 老许,你要转Flutter不要?只要你开金口,面试题现在就给你送来

    概述 Flutter是Google推出的一套开源跨平台UI框架,可以快速地在Android.iOS和Web平台上构建高质量的原生用户界面.在过去的一年里,Flutter的更新频率是相当的快,也有很多的 ...

  8. Flutter 仿滴滴出行App,2021最新华为Android校招面试题

    项目结构:详见作者另外一个Flutter完整项目flutter_wanandroid.

  9. 打开Flutter动画的另一种姿势——Flare,android面试题选择题

    注册登陆 然后进入 2D - Animation Tools for Apps, Games, and Web 首先,注册好账号,如果有Google账号,可以直接使用. 登陆成功后则可以开始创建动画了 ...

最新文章

  1. vue-cli启动项目运行_SpringBoot2.0 基础案例(17):自定义启动页,项目打包和指定运行环境...
  2. 前端学习(2968):完善登录页面
  3. python处理图片隐写分析_Python3简单实现隐写术
  4. 【BZOJ-14492895】球队收益球队预算 最小费用最大流
  5. 设计模式之strategy模式(C++实现)
  6. js代码测试。【一定要在真实工程下来测试是否好用】
  7. DataFrame与Dataset 的区别
  8. ruby操作常用数据库 - 使用DBI[翻译 转帖]
  9. phpMyAdmin下载、安装和使用入门教程
  10. 【读书笔记】之蔡康永的说话之道
  11. 你和你的女神之间,差了一个OpenCV口红色号识别器
  12. CVTE+网易+微盟面经
  13. anaconda安装支持mpi并行化的h5py
  14. java LocalDateTime 加时间,计算两个时间的差
  15. ninja 编译threadx(ubuntu)
  16. error: redefinition of ‘xxx’问题的解决
  17. 怎么找回xmind意外关机的文件_如何在意外关机后恢复文件
  18. 基于cnn-lstm的交通流量预测
  19. 大数据分析数据分析师培训学什么
  20. linux ftp cmd被动模式,如何在Windows命令提示符下使用被动FTP模式?

热门文章

  1. php通用下载方法,PHP实现下载断点续传的方法
  2. 造轮子了!NETCore跨平台UI框架,CPF
  3. Word2010中,空格显示为省略号(点)的解决办法!
  4. 小米Pro15安装Ubuntu20.04LTS后Window10的时间提前了8小时 , 的解决办法 2021-03-04 16:50
  5. 服务器部署rz/sz
  6. 关于kindeditor富文本编辑的上传图片、音频、和视频的使用
  7. 【源码+教程】Java桌球游戏_Java初级项目_Java练手项目_Java项目实战_Java游戏开发
  8. STM32F103(库函数)——点亮LED并且使用软件延时实现led闪烁
  9. Linux Xshell连接不到虚拟机 -- Could not connect to ‘xxx.xxx.xxx.xxx‘ (port 22): Connection failed
  10. 【GAOPS038】数据链路层PPP和HDLC协议