主题 : 《Linux 基础》教案第七章 Linux内核的管理与定制
我为人人,人人为我
级别: 七朵秋菊

UID: 13542
精华: 0
发帖: 1211
威望: 47453 点
无痕币: 23241 WHB
贡献值: 0 点
在线时间: 437(时)
注册时间: 2008-02-19
最后登录: 2023-08-15

0 《Linux 基础》教案第七章 Linux内核的管理与定制


《Linux 基础》教案
第七章 Linux内核的管理与定制




1.    回顾上一章: [10分钟]    3
2.    课程知识点讲解:    3
2.1.    核心基础    3
2.2.    升级核心前的准备    4
2.2.1.    查看系统中的设备    4
2.2.2.    核心源代码的获取与安装    6
2.3.    内核的定制    8
2.3.1.    模块的概念与作用    9
2.3.2.    内核定制的方式    10
2.3.3.    内核定制过程概述    12
2.4.    内核与模块的编译与安装    12
2.4.1.    编译、安装内核文件    12
2.4.2.    更新配置文件    12
2.4.3.    模块的安装与管理    12
3.    本章总结  [10分钟]    13
4.    考核点    13
5.    测试题    13
6.    扩展部分:    13
7.    学员问题汇总:    19
8.    作业:    19





























授课教师:师资培训
课时:2小时


    本章主要的目的

    了解Linux内核的作用和基本功能
    获取Linux内核的源码包,并进行安装
    掌握内核的多种配置方法
    了解内核配置项的含义
    掌握内核的编译方法
    掌握内核模块的编译与安装
    在Linux系统中应用新内核

    本章重点

    获取Linux内核的源码包,并进行安装
    掌握内核的多种配置方法
    掌握内核的编译方法
    掌握内核模块的编译与安装


    本章难点

    获取Linux内核的源码包,并进行安装
    掌握内核的编译方法


1.    回顾上一章:    [10分钟]

    Linux应用程序基础
    RPM包管理
    应用程序编译
    库管理

2.    课程知识点讲解:    
2.1.    核心基础
    Linux 拥有现在操作系统所具有的很多功能:
    真正的抢先式多任务处理,支持多用户
    内存保护
    虚拟内存
    支持对称多处理SMP(symmetric multiprocessing),即多个CPU机器
    符合POSIX标准
    网络功能完善
    图形用户接口和桌面环境
    速度和稳定性
严格说,Linux 并不是一个完整的操作系统。当我们在安装通常所说的Linux 时,我们实际安装的是很多工具的集合,这些工具协同工作以组成一个功能强大的实用系统。Linux 本身只是这个操作系统的内核,是操作系统的心脏、灵魂、指挥中心。整个系统应该称为GNU/Linux 。
内核是一个操作系统的核心,它负责管理系统的进程、内存、设备驱动程序、文件和网络系统,决定着系统的性能和稳定性。内核以独占的方式执行最底层任务,保证系统正常运行,协调多个并发进程,管理进程使用的内存,使它们互相之间不产生冲突,满足进程访问磁盘的请求等等。

为什么要学习使用内核
    通过阅读内核源代码,可以了解操作系统的工作原理;
    可以根据主机硬件的具体情况,定制Linux内核,这样就需要重新编译内核;
    对内核源代码进行修改,以满足特定功能的需要,并且可以把对内核的修改作为内核补丁进行发布,让更多地人分享你的成果。

为什么要升级内核
Linux 发行版本中的内核不一定适用于所有的系统,配置与升级内核有利于用户解决系统中的许多问题:
    现在内核中会不断暴露出漏洞,需要打补丁后重新编译内核,以便系统能够更加安全地运行;
    新的内核版本通常会提供用户所需要的新功能;
    新的内核版本会支持较新的硬件设备正常工作;
    正确地为主机配置个性化的内核会使系统运行得更加快速、稳定。
2.2.    升级核心前的准备
需要充分掌握系统中的硬件信息以便正确配置内核选项、获得Linux 内核的源码包。


2.2.1.    查看系统中的设备

我们可以通过命令和相应的文件来查询系统中的设备信息,充分了解系统中的硬件信息对于进行内核配置大有益处。

(1). 查看主机的CPU信息
命令:more  /proc/cpuinfo



(2). 查看主机PCI 设备信息

目前主机的许多设备都属于PCI设备,那么如何来查看PCI设备信息

命令:lspci




(3). 查看当前的Linux 操作系统所使用的内核模块(module)

在对新内核进行配置时应充分参考当前Linux 内核的配置,查看当前内核模块的使用情况并作为配置新内核的依据。“module”文件中包含了当前Linux 操作系统所使用的内核模块。

命令: more  /proc/modules



2.2.2.    核心源代码的获取与安装

一、获取Linux 内核源代码

(1)    从发行版本中获得Linux 内核源代码。
在各种知名的Linux发行版本中都会包含Linux 内核源代码包,以便用户可以对Linux 内核进行定制和打补丁。
在Red Hat Linux 9的第二张安装光盘中包含Linux内核的源代码包,文件名是“kernel—source—2.4.20—8.i386.rpm”。

(2)    从网络下载Linux 的内核源代码。
对于Linux内核,有很多网站可以提供源代码的下载
①    从Linux内核的官方站点下载最新的Linux内核源代码。
Linux内核官方站点(http;//www.kernel.org)负责Linux内核的权威发布,用户可以到该站点上下载内核的最新发布。



在kernel.org站点中提供了Linux内核各个大的版本的最新下载(包括稳定版和开发版),用户可以在该站点以第一时间下载最新的Linux 内核版本。Linux内核源代码以压缩包的形式提供,文件名类似“Linux-2.4.24.tar.bz2”。

②    从知名的Linux内核网站下载Linux内核版本的下载,在这里我们介绍一个具有代表性的站点“linuxhq.com” (http;//www.linuxhq.com/kernel)。
“linuxhq.com”最大的特点就是信息全面,在其中可以快速查询到Linux内核的各个版本的信息并进行下载,对于需要获得Linux内核某个特定版本的用户特别方便。

二、安装Linux内核源代码

Linux内核源代码以打包的形式提供,rpm和bz2两种格式的源码包的安装方法不同

(1)    安装Red Hat Linux 9中的RPM内核源码包

    # rpm -ivh kernel-source-2.4.20-8.i386.rpm

(2)    安装网络下载的内核源码包

    # tar jxvf linux-2.4.24.tar.bz2





2.3.    内核的定制
内核版本号

  由于Linux的源程序是完全公开的,任何人只要遵循GPL,就可以对内核加以修改并发布给他人使用。Linux的开发采用的是集市模型(bazaar,与cathedral--教堂模型--对应),为了确保这些无序的开发过程能够有序地进行,Linux采用了双树系统。

  一个树是稳定树(stable tree),另一个树是非稳定树(unstable tree)或者开发树(development tree)。一些新特性、实验性改进等都将首先在开发树中进行。如果在开发树中所做的改进也可以应用于稳定树,那么在开发树中经过测试以后,在稳定树中将进行相同的改进。一旦开发树经过了足够的发展,开发树就会成为新的稳定树。

  开发数就体现在源程序的版本号中;源程序版本号的形式为x.y.z:对于稳定树来说,y是偶数;对于开发树来说,y比相应的稳定树大一(因此,是奇数)。到目前为止,稳定树的最高版本是2.2.16,最新发布的Redhat7.0所采用的就是2.2.16的内核;开发树的最新版本是2.3.99。也许你已经发现和多网站上都有2.4.0-test9-pre7之类的内核,但是这并不是正式版本。内核版本的更新可以访问http://www.kernel.org
  为什么重新编译内核

  Linux作为一个自由软件,在广大爱好者的支持下,内核版本不断更新。新的内核修订了旧内核的bug,并增加了许多新的特性。如果用户想要使用这些新特性,或想根据自己的系统度身定制一个更高效,更稳定的内核,就需要重新编译内核。

  通常,更新的内核会支持更多的硬件,具备更好的进程管理能力,运行速度更快、 更稳定,并且一般会修复老版本中发现的许多漏洞等,经常性地选择升级更新的系统内核是Linux使用者的必要操作内容。

  为了正确的合理地设置内核编译配置选项,从而只编译系统需要的功能的代码,一般主要有下面四个考虑:

  自己定制编译的内核运行更快(具有更少的代码)

  系统将拥有更多的内存(内核部分将不会被交换到虚拟内存中)

  不需要的功能编译进入内核可能会增加被系统攻击者利用的漏洞

  将某种功能编译为模块方式会比编译到内核内的方式速度要慢一些


2.3.1.    模块的概念与作用

一、模块简介
  
  Windows NT是一种微内核的结构,其内核的功能块被划分成独立的模块,在这些功能块之间有严格的通信机制;而Linux则不同,它是一种monolithic(单一大块)结构,也就是说,整个内核是一个单独的、非常大的程序。在这种结构中,部件的添加和删除都相当麻烦,需要重新编译内核。为了解决这个问题,不知道从哪个版本的内核开始,Linux引入了一种称为module(模块)的技术,可以把某些功能代码作为模块动态装载到内核中使用。
  
  模块是一种目标对象文件,需要在内核空间执行,可以把它看作是一组已经编译好而且已经链接成可执行文件的程序。在需要的时候,内核就会实用某种方法调用这些程序来执行特定的操作,实现特定的功能。内核在内核符号表中维护了一个模块的链表,每个符号表对应一个模块,在把模块加载进内核时正确地对其进行解释,并将模块作为内核的一部分来执行;加载进内核中的模块具有所有的内核权限。模块可以在系统启动时加载到系统中,也可以在系统运行的任何时刻加载;在不需要时,可以将模块动态卸载。这样就不用每次修改系统的配置时都要重新编译内核了。
  
  二、模块的优缺点
  
  内核模块的这种动态装载特性具有以下的优点:

  1、可以把内核映像文件保持在最小。在编译内核时可以选择把一部分内容当成模块进行编译,这样在最终生成的内核映像文件中就可以不包含这部分内容,从而生成最小的内核映像文件。
  2、灵活性好。如果需要实用新的模块,不必重新编译内核,只要把新的模块编译后装载进系统中就可以了。如果对内核源程序进行了修改,也不需要重新编译整个内核,只需要修改对应的部分就可以了。
  
  但是,内核模块的引入也带来了一些问题:

  1、这种动态加载的特性不利于系统的性能和内存的利用,会带来负面的影响。
  2、装入内核的模块和其他内核部分一样具有最高的权限,使用不当就可能引起系统的崩溃。
  3、内核版本和模块版本的不兼容也会导致系统的崩溃,因此必须进行严格的版本检查,这样就使模块的编写变得更加复杂了。
  4、有些模块要使用其他模块(例如VFAT就要使用FAT)的内容,模块之间存在一定的依赖关系,这样模块的实用就复杂化了。
  
  由于模块的这种动态装载/卸载的特性,在Linux中大部分设备驱动程序都是使用模块来编写的,例如文件系统(minix、msdos、isofs、smbms、nfs、proc等等)、SCSI设备驱动程序、以太网驱动程序、CD-ROM驱动程序等等。下面让我们介绍一下模块的使用方法。

2.3.2.    内核定制的方式

    文本交互 配置界面
首先进入需要配置的内核源代码目录
cd /usr/src/linux-2.4
使用
make config
            进入文本交互的配置界面。

    文本窗口配置界面

Linux内核文本窗口配置界面在字符终端上实现了基于窗口和对话框的交互配置界面,在对操作环境要求较低的情况下实现了较好的用户配置界面。

(1) 启动文本窗口配置界面
首先进入需要配置的内核源代码目录
cd /usr/src/linux-2.4
使用
make menuconfig
                进入Linux内核的文本窗口配置界面。

(2)文本窗口的主菜单配置界面


    图形窗口配置界面

Linux 内核在图形窗口配置界面在X-Windows环境下运行,具有界面友好、操作方便的优点。
首先进入需要配置的内核源代码目录
cd /usr/src/linux-2.4
使用
make xconfig
                进入Linux内核的图形窗口配置界面。

内核的图形窗口配置界面可以使用鼠标进行操作



内核配置项设置界面


Y    配置某功能编译进内核

M    配置某功能作为模块编译

N    配置不使用某功能(既不编译进内核,也不作为模块编译)

    根据原有配置文件自动生成新的配置文件

make oldconfig 命令将根据现有的内核配置文件生成新的配置文件,从而有效地避免大量手工配置内核的工作。
首先进入需要配置的内核源代码目录
cd /usr/src/linux-2.4
使用
make oleconfig
                命令将根据现有的内核配置文件生成新的配置文件


2.3.3.    内核定制过程概述

可装载模块支持
    在通常的Linux系统中都需要对该项进行支持,否则内核将不能使用内核模块。

处理器


常规设置


网络设置



无论采用哪种方法对Linux内核进行配置,最终的目的都是为了生成内核配置文件“.config”。

    内核的编译过程将完全按照“.config”文件中的配置内容进行编译。

2.4.    内核与模块的编译与安装
2.4.1.    编译、安装内核文件

    make dep:生成依赖关系

在编译内核前,需要使用“make dep”命令生成内核功能间的依赖关系,为编译内核做准备。
    make bzImage:编译内核

使用“make bzImage”命令进行内核编译,编译过程将持续相当长的时间(10分钟以上),请耐心等候。

bzImage 文件
    “arch/i386/boot/ ”目录下的bzImage 文件是新编译生成的内核文件。

    make modules:编译内核模块

使用“make modules”命令编译内核模块,编译过程将持续相当长的时间(10分钟以上)。

    make modules_install:安装内核模块

内核模块编译好后需要安装到Linux系统的相应目录中才可以使用,使用“make modules_install”命令安装内核模块 。

    make install:安装内核

使用“make install”命令安装新内核到系统中 ,并且自动为使用新内核做必要的配置。

2.4.2.    更新配置文件

(1)    查看新安装的内核文件

Red Hat Linux 9 中系统启动所需的文件都放在了目录“/boot”下,其中也包括内核文件。在“/boot”目录下可以找到新编译生成的内核文件。

(2)    查看系统引导程序配置文件—grub.conf

新编译的内核需要在GRUB系统引导程序中进行配置后才能够用于引导系统,GRUB系统引导程序的配置文件是“/etc/grub.conf ”。

2.4.3.    模块的安装与管理

模块的使用
  
  1、模块的查询
  
  我们可以使用lsmod命令来了解系统中现在装载进来了哪些模块。例如,在笔者机器上执行的结果为(注意,以下介绍的这些命令(包括lsmod)只有超级用户才可以执行):
  
  Module Size Used by
  lockd 30344 1 (autoclean)
  sunrpc 52132 1 (autoclean) [lockd]
  rtl8139 11748 1 (autoclean)
  
  其中Module列是模块的名字,Size是显示的模块的大小,Used by列表示引用次数,圆括号中的autoclean表示该模块可以在空闲时自动卸载,中括号中的[lockd]表示模块lockd会引用sunrpc模块的内容。
  
  
  2、模块的装载
  
  模块的装载有两种方法:一种是实用insmod命令手工加载模块,第二种方法是使用内核守护进程kerneld在需要的时候动态装载。insmod命令的格式为:
  
  insmod //modulename.o
  
  值得注意的是,insmod命令需要知道模块存放的位置,这样才能在内核符号表中进行解析。模块可以位于当前路径中,也可以在insmod命令中指明绝对路径,另外还有几个相关的配置文件可以说明模块的位置(见后文中的介绍)。
  
  kerneld是一个标准的守护进程,具有超级用户的权限,其主要功能是加载和卸载核心模块, 但是它还可以执行其他任务, 如通过串行线路建立PPP连接并在适当时候关闭它。kerneld自身并不执行这些任务,它通过某些程序如insmod来做此工作。它只是内核的代理,为内核进行调度。这个守护进程仅仅是一个带有超级用户权限的普通用户进程。当系统启动时它也被启动并为内核打开了一个进程间通讯(IPC)通道,内核需要执行各种任务时就实用这个IPC来向kerneld发送消息。例如,如果内核请求现在还没有装载到系统中的文件系统,那么就通知kerneld装载这个文件系统,然后内核就可以使用这个文件系统了。在模块空闲时(即没有其他进程使用这个模块时),kerneld还可以动态卸载这个模块。
  
  需要注意的是,如果模块之间有某种引用关系,那么装载模块时必须遵循一定的次序。例如,上面lsmod显示的结果中lockd模块要引用sunrpc的内容,那么必须首先装载sunrpc之后才能装载lockd,否则就会出错。
  
  
  3、模块的卸载
  
  我们可以使用rmmod命令把模块从系统中卸载出去,该命令的格式为:
  
  rmmod modulename
  
  需要注意的是,模块只有在空闲时才能够从系统中卸载出去。lsmod输出结果中的Used by一列就说明了模块当前的状态。如果该值不为0,说明模块正忙,不能卸载;否则该值为0,说明模块空闲,可以从系统中卸载出去。对于繁忙的设备,我们首先得断开对应设备的连接,然后才能删除对应的模块。例如,我们要卸载模块rtl8139(这个模块是笔者机器中rtl8139的以太网卡对应的模块),我们首先要断开网络连接:
  
  ifdown eth0 /* eth0是笔者机器中的第一块网卡*/
  
  现在再执行lsmod命令的输出结果为:
  
  Module Size Used by
  lockd 30344 1 (autoclean)
  sunrpc 52132 1 (autoclean) [lockd]
  rtl8139 11748 0 (autoclean)
  
  说明已经没有设备再使用rtl8139了,我们可以使用
  
  rmmod rtl8139
  
  命令将其从系统中卸载出去。
  
  标志为autoclean(见有关lsmod的介绍)的模块可以自动卸载。前面我们已经提到,模块之间可能会有引用关系。如果A模块引用了B模块的内容,那么必须先装载B模块之后才能成功装载A模块;在卸载B模块之前也要首先卸载A模块,否则就会导致系统的崩溃(当然,如果模块源程序编写的正确,在卸载A模块之前,B模块是无法卸载的)。
  
  4、模块实用工具
  
  以上我们介绍的lsmod、insmod、rmmod是一组实用工具所提供的三个命令,这组实用工具一般是和内核版本对应的,其1.3.57版本名为modules(modules-1.3.57.tar.gz),高一点的版本名为modutils(例如modutils-2.4.2.tar.gz)。最好保证你的系统中的模块实用工具的版本号(可以使用modinfo -V命令来查看)不低于内核版本号(可以使用uname -r来查看)。1.3.57版本的modules内容包括modprobe、depmod、genksyms、makecrc32、insmod、rmmod、lsmod、ksyms、kerneld等命令。其中modprobe和insmod命令类似,不过它要依赖于相关的配置文件;depmod用于生成模块依赖文件/lib/modules/kernel-version/modules.dep;genksyms和ksyms与内核函数的版本号有关(由于内核的不断更新,各个版本的内核函数各有不同,为了不会引起系统的崩溃,内核源程序中要对内核函数的版本号进行严格地控制)。在以后版本的实用工具中,使用kmod来取代了kerneld。kmod的功能和kerneld类似,但是它不能自动卸载模块。之所以采用kmod的原因在于kerneld是使用IPC通道实现的,相当于多经过了一层处理,另外kerneld的代码也比较复杂,kmod的代码数量也比kerneld少得多。
  
  
  5、与模块有关的内核编译选项和过程
  
  在使用make confing / make menuconfig / make xconfig对内核进行配置时,和模块有关的选项有:
  Code maturity level options -->
  Prompt for development and/or incomplete code/drivers
  此选项为代码的成熟程度。所有新的设计与改进都首先在开发版(版本号为x.y.z,其中y是奇数)中试用,经过验证技术可行之后再在稳定版(版本号为x.y.z,其中y是偶数)中正式引入。尚不成熟或不完善的技术在默认的情况中是不会编译到内核中的,如果你希望试验这些内容(例如2.4.*版本中的khttpd、IPV6等),就要选中这个选项。
  >
  Loadable module support -->
  Enable module support
  Set version information on all module symbols
  Kernel module loader
  此选项是对可装载内核的支持以及对模块符号的版本号、内核模块装载程序支持的选项。对于其他大部分选项来说,你可以将相应的代码编译到内核中(使用build-in方式),也可以将他们编译成模块(使用module)方式。
  
  如果你选用了模块方式,那么在编译内核的过程中,你除了要使用
  
  make; make install
  
  命令来编译/安装内核之外,还要使用
  
  make modules; make modules_install
  
  来编译/安装内核模块。编译好的模块被安装到/lib/modules/kernel-version/目录中。
  
  编译过程中还要运行一个
  
  depmod -a
  
  命令。这个命令生成模块依赖文件,也就是/lib/modules/kernel-version/modules.dep,该文件格式为:
  
  /lib/modules/2.2.14-5.0/fs/autofs.o:
  
  /lib/modules/2.2.14-5.0/fs/binfmt_aout.o:
  
  /lib/modules/2.2.14-5.0/fs/binfmt_java.o:
  
  /lib/modules/2.2.14-5.0/fs/binfmt_misc.o:
  
  /lib/modules/2.2.14-5.0/fs/coda.o:
  
  /lib/modules/2.2.14-5.0/fs/fat.o:
  
  /lib/modules/2.2.14-5.0/fs/hfs.o:
  
  /lib/modules/2.2.14-5.0/fs/hpfs.o:
  
  /lib/modules/2.2.14-5.0/fs/lockd.o: /lib/modules/2.2.14-5.0/misc/sunrpc.o
  
  /lib/modules/2.2.14-5.0/fs/minix.o:
  
  /lib/modules/2.2.14-5.0/fs/msdos.o: /lib/modules/2.2.14-5.0/fs/fat.o
  
  ......
  
  这个文件中详细列出了所有的模块文件的绝对路径,每一行说明一个模块的信息;如果一行中有多个模块的信息,就说明了模块间具有依赖关系。例如,
  
  /lib/modules/2.2.14-5.0/fs/lockd.o: /lib/modules/2.2.14-5.0/misc/sunrpc.o
  这一行就说明模块lockd要引用sunrpc模块。有了这个文件,内核在装载模块时就可以根据所解析出的模块名来正确地定位模块的位置了。
  
  
  6、与模块有关的配置文件
  
  和模块有关的文件,除了上面这个modules.dep之外,还有几个配置文件。例如:
  
  /etc/rc.d/rc.modules
  /etc/conf.modules或/etc/modules.conf
  
  例如笔者机器中后一个文件的内容为:
  
  alias eth0 rtl8139
  alias sound-slot-0 via82cxxx
  
  分别说明了网卡和声卡的类型,例如第一行中eth0是我的第一块网卡,rtl8139是对应的模块,系统会查找/lib/modules/2.2.14-50/modules.dep文件,在其中找到
  
  /lib/modules/2.2.14-5.0/net/rtl8139.o:
  
  这一行,从而就可以定位正确的模块文件。
  
  7、单独编译模块
  
  我们除了可以在内核源程序树中使用
  
  make modules; make modules_install
  
  来编译安装内核模块之外,也可以自行对其进行编译,相关的编译选项有:
  
  __KERNEL__--这个标志告诉头文件此代码将在内核模块中运行,而不是作为用户进程的一部分运行。
  
  MODULE--这个标志告诉头文件要为内核模块给出适当的定义。
  
  LINUX--从技术上讲,这个标志不是必要的。但是,如果你希望写一个比较正规的内核模块,它可以在多个操作系统上编译,这个标志将会使你感到非常方便。它可以允许你在独立于操作系统的部分进行常规的编译。
  
  还有其它一些可被选择包含标志,这取决于编译模块使用的选项。如果你不能确定内核应该怎样编译,可以在/usr/include/linux/config.h中查到。
  
  __SMP__--对称多处理。如果要把内核编译成可以支持对称多处理,那么必须定义这个标志
  
  CONFIG_MODVERSIONS--如果CONFIG_MODVERSIONS被激活(也就是说要区分内核模块的版本号),你需要在编译内核模块时定义这个标志并包含头文件/usr/include/linux/modversions.h。
  
  例如,我们自行下载rtl8139网卡的驱动程序的源程序rtl8139.c,可以这样编译:
  
  gcc -Wall -O2 -DMODULE -D__KERNEL__ -DLINUX -o rtl8139.o rtl8139.c
  
  然后修改前面介绍的相应的配置文件或者使用insmod命令就可以使用这个模块了。
  
  
  8、相关问题
  
  再次强调,模块实用工具的版本号最好不要低于内核的版本号。例如,如果你的modutils的版本号小于2.4.0,那么在你自己下载2.4.*版本的内核来编译时,即使各个步骤都完全正确,你会发现/lib/modules/kernel-version/modules.dep这个文件为空,即使你自己手工修改了这个文件,重新启动机器之后,这个文件又变成空了。所以对于这种情况,你应该使用2.4.*的modutils。2.2和2.4版本的内核模块存储的路径有很大的差别,/etc/conf.modules文件的结构也很不相同了,感兴趣的读者可以自行试验一下。  

















     老师提问:
问题1:
问题2:
        
    ……
    知识点讲解n
3.    本章总结     [10分钟]
4.    考核点
  考核点1:
  考核点2:
5.    测试题
  测试题1:
  测试题2:

6.    扩展部分:
     扩展部分1:



  扩展部分2:
  扩展部分3:        
7.    学员问题汇总:
  学员问题1:    
  学员问题2:    
8.    作业:
  习题1:
  习题2:
  习题3:
Total 0.150071(s) query 3, Time now is:05-17 10:07, Gzip enabled 粤ICP备07514325号-1
Powered by PHPWind v7.3.2 Certificate Code © 2003-13 秋无痕论坛