目录
实验一:操作系统简介
实验二:内存管理
实验三:进程管理
实验四:中断和异常管理
实验五:内核时间管理
实验六:设备管理
实验七:文件系统
实验八:网络管理
实验九:内核虚拟化
实验一:操作系统简介
配置yum更新源
cd /etc/yum.repos.d/
[base]
name=EulerOS-2.0SP8 base
baseurl=http://mirrors.huaweicloud.com/euler/2.8/os/aarch64/
enabled=1
gpgcheck=1
gpgkey=http://mirrors.huaweicloud.com/euler/2.8/os/RPM-GPG-KEY-EulerOS
[base]
name=openEuler20.03LTS
baseurl=https://repo.openeuler.org/openEuler-20.03-LTS/OS/aarch64/
enabled=1
gpgcheck=0
任务1:
yum makecache 更新yum源
备份
sz boot_origin.tgz 将备份文件发送到本地
旧版本
将系统盘备份
下载内核源码zip包
安装依赖的组件以及一些工具
yum install elfutils-libelf-devel
yum install ncurses-devel
yum install openssl-devel
yum install bc
yum install bison
yum install flex
yum install ncurses-devel
开始编译
编译成功
make modules_install安装模块,大概两分钟。
make install 安装内核
……
重启之后
选择编译的内核进入
任务2:内核模块编程
Linux 提供了一种动态加载内核的机制,这种机制称为模块(Module)。
内核模块是具有独立功能的程序。
它可以被单独编译,但是不能单独运行,它的运行必须被链接到内核作为内核的一部分在内核空间中运行。
模块具有一下特点:
1) 模块本身不被编译入内核映像,从而控制了内核的大小;
2) 模块一旦被加载,它就和内核中的其它部分完全一样。
编写hello.c程序和相应的Makefile
Makefile如下
make
查看编译后的文件目录结构
加载模块 sudo insmod hello.ko
使用命令 lsmod 查看模块是否被加载 如下:
查看加载内容 sudo dmesg | tail -n 2 (可以看到打印的信息)
卸载hello模块 rmmod hello
查看卸载内容 dmesg | tail -n 1
实验二:内存管理
任务一:使用 kmalloc 分配 1KB,8KB的内存,并打印指针地址
- 使用 kmalloc 分配 1KB,8KB的内存,打印指针地址;
- 查看已分配的内存,根据机器是32位或64位的情况,分析地址落在的区域。
kmalloc()函数:
在设备驱动程序或者内核模块中动态分配内存
分配成功时,返回分配的虚拟地址;分配失败时,返回NULL。
1.创建一个kmalloc-module目录
编写kmalloc.c 与 Makefile
编译 make
加载模块 insmod kmalloc.ko
使用命令 lsmod 查看模块加载内容 如下:
卸载模块 查看日志
查看系统配置页面的大小 4KB
kmallocmem1 addr = ffff97a3c51dc000
kmallocmem2 addr = ffff97a3d65ae000
用户内存空间地址是从0000000000000000起始到00ffffffffffffff结束,其余内存地址均属于内核内存空间,kmalloc 分配的内存地址,位于内核空间。
任务二:使用vmalloc分别分配8KB、1MB、64MB的内存,打印指针地址
vmalloc()函数功能是在设备驱动程序或者内核模块中动态分配内存,且分配的内存是内核内存。
头文件:#include <linux/vmalloc.h>
分配内存以字节为单位,成功返回分配的虚拟地址;分配失败时,返回NULL。
vmalloc函数的工作方式类似于kmalloc,只不过前者分配的内存虚拟地址是连续的,而物理地址则无需连续。它通过分配非连续的物理内存块,再修改页表,把内存映射到逻辑地址空间的连续区域中。通过vmalloc获得的页必须一个一个地进行映射,效率不高,因此,只在不得已(一般是为了获得大块内存)时使用。
kmalloc能分配的大小有限,vmalloc能分配的大小相对较大,但是vmalloc比kmalloc速度要慢。
1.先编写vmalloc.c 以及对应的Makefile
2.进行编译 并查看编译后生成文件
3. 将模块加载进内核并查看
4.将模块卸载并查看
可以看出分配的是内核空间的内存。
任务三:
内存泄漏
内存泄漏指的是程序中己动态分配的内存未释放或无法释放,从而产生内存泄漏。
内存泄漏的危害:
1.可用的内存越来越少,堆积后的后果就导致内存溢出;
2.导致其他应用程序无法使用内存
3.应用程序访问内存时,不停地产生缺页错误;
4.使得CPU不停地从磁盘上的swap空间读取页面数据,导致应用程序性能下降,cpu无法进行其他工作。
如何防止内存泄漏
1.使用自动控制内存的语言,如JAVA
2.在使用手动控制内存的语言时一定要注意在分配了内存之后要free掉。
3.使用内存泄露检测器,在编写代码过程中对代码进行检测
内存溢出
内存溢出指的是程序在申请内存时,没有足够的内存空间供其使用。
内存溢出的危害:
1.程序无法运行,有时候会自动关闭软件;
2.易遭受缓冲区溢出攻击/黑客攻击。
如何防止内存溢出:
注意不要出现内存泄漏即可。
内存越界
内存越界指的是程序向系统申请一块内存后,使用时超出申请范围。
内存越界的危害:
导致内存越界错误,程序向内存块中写入数据,超过内存块的边界,写到了其他内存对象中,导致覆盖了其他内存对象中的数据。
防止内存越界:
1.使用安全的语言
2.使用安全的函数库
3.边界检测,防止越界的发生
实验三:进程管理
任务一:创建并运行内核线程
内核线程:
内核经常需要在后台执行一些操作,这种任务就可以通过内核线程(kernle thread)完成,内核线程是指独立运行在内核空间的标准进程。内核线程和普通的进程间的区别在于:内核线程没有独立的地址空间,mm指针被设置为NULL;它只在内核空间运行,从来不切换到用户空间去;并且和普通进程一样,可以被调度,也可以被抢占。
内核线程只能由其它的内核线程创建,Linux内核通过给出的函数接口与系统中的初始内核线程kthreadd交互,由kthreadd衍生出其它的内核线程。
1.首先编写kthread.c 以及相应的Makefile
2.编译并查看编译后的文件
3.加载模块并查看打印信息
4.卸载模块
可以看到卸载模块后杀死了改内核进程
任务二:打印输出当前系统 CPU 负载情况
proc文件简介
proc 文件系统是 Linux 中的特殊文件系统,提供给用户一个可以了解内核内部工作过程的可读窗口,在运行时访问内核内部数据结构、改变内核设置的机制。
proc文件系统能够保存系统当前工作的特殊数据,但并不存在于任何物理设备中,对其进行读写时,才根据系统中的相关信息即时生成。所有proc文件挂载在/proc目录下。
/proc 的文件可以用于访问有关内核的状态、计算机的属性、正在运行的进程的状态等信息。大部分 /proc 中的文件和目录提供系统物理环境最新的信息。它们实际上并不存在磁盘上,也不占用任何空间。(用ls –l 可以显示它们的大小)当查看这些文件时,实际上是在访问存在内存中的信息,这些信息用于访问系统。
尽管 /proc 中的文件是虚拟的,但它们仍可以使用任何文件编辑器或像 'more'、'less' 或 'cat' 这样的程序来查看。
1.编写cpu_loadavg.c 以及相应的Makefile文件 该程序用来查看
2. make 并查看编译后产生的文件
3.加载内核模块并查看模块打印信息
4.卸载内核模块并查看模块打印信息
任务三:打印输出当前处于运行状态的进程的 PID 和名字
当前进程在在/proc文件系统也有保存(如2.1所述),只不过需要遍历所有进程文件夹,从stat文件中读取状态,来判定是否为当前运行进程。而内核中可用进程遍历函数来遍历所有进程,且进程描述符task_struct结构里边有state状态,state为0的进程就是当前进程。
1.编写对应的源文件process_info.c 以及对应的Makefile
2. make 并查看编译后产生的文件
3.加载内核模块并查看模块打印信息
可以看到当前两个进程的pid
4.卸载内核模块并查看模块打印信息
任务4:使用 cgroup 实现限制 CPU 核数
首先,需对libcgroup进行安装
依次进行cgroup文件夹的挂载,cpuset子系统的挂载,设置cpu核数如下:
编写一个简单的死循环程序如下:
在cpuset中运行这个死循环程序:
不要关闭上述终端,另打开一个终端,执行以下命令,查看此时系统资源负载情况
任务五:使用 cgroup 实现不允许访问U盘
1.插入U盘,使用fdisk -l获取该U盘盘符。此处是/dev/sdb1
2. 调用shell命令 “ls -l”获取设备号 ls -l /dev/sdb1
设备号为8,17
3. 将U盘挂载到当前系统中
mkdir /usb
mount /dev/sdb1 /usb
4、挂载设备管理devices子系统
cd /cgroup/
mkdir devices
mount -t cgroup -o devices devices /cgroup/devices #挂载devices子系统
cd /cgroup/devices
mkdir mydevices # 创建mydevices控制组
cd mydevices
5. 设置拒绝U盘访问
这里的8:17就是我们上文中得到的设备号,将相关设置写入devices.deny文件实现拒绝u盘访问。
6.进行验证
终端显示打开失败。不允许访问u盘设置成功。
当允许访问U盘时,上述运行结果是
实验四:中断和异常管理
任务一:使用tasklet实现打印helloworld
1.编写对应的源文件tasklet_intertupt.c 以及对应的Makefile
‘
2. make 并查看编译后产生的文件
3.加载内核模块并查看模块打印信息
4.卸载内核模块并查看模块打印信息
任务二:用工作队列实现周期打印helloworld
1.编写对应的源文件tasklet_intertupt.c 以及对应的Makefile
2. make 并查看编译后产生的文件
3.加载内核模块并查看模块打印信息
工作队列延时 5*HZ(5秒)开始执行,对应上图中模块加载后5秒才打印HelloWorld!;而后每次执行工作队列中间休眠15秒
4.卸载内核模块并查看模块打印信息
任务三:编写一个信号捕获程序,捕获终端按键信号
Linux信号处理机制
基本概念
Linux提供的信号机制是一种进程间异步的通信机制,每个进程在运行时,都要通过信号机制来检查是否有信号到达,若有,便中断正在执行的程序,转向与该信号相对应的处理程序,以完成对该事件的处理;处理结束后再返回到原来的断点继续执行。实质上,信号机制是对中断机制的一种模拟,在实现上是一种软中断。
信号的产生
用户:用户能够通过终端按键产生信号,内核:当进程执行出错时,内核会给进程发送一个信号,进程:一个进程可以通过系统调用kill给另一个进程发送信号,一个进程可以通过信号和另外一个进程进行通信。
当信号发送到某个进程中时,操作系统会中断该进程的正常流程,并进入相应的信号处理函数执行操作,完成后再回到中断的地方继续执行。
每个信号都有自己的响应动作,当接收到信号时,进程会根据信号的响应动作执行相应的操作,信号的响应动作有以下几种:中止进程(Term),忽略信号(Ign),中止进程并保存,内存信(Core),停止进程(Stop),继续运行进程(Cont)。
ctrl+c ----> SIGINT(终止、中断)
ctrl+\ ----> SIGQUIT(退出)
ctrl+z ----> SIGTSTP(暂时、停止)
1.源代码如下:
编译
测试如下:
实验五:内核时间管理
任务一:调用内核时钟接口打印当前时间
1.编写对应的源文件current_time.c 以及对应的Makefile
2. make 并查看编译后产生的文件
在本地编译报错,可能是内核版本的问题。本地内核版本5.10.0,云服务器上版本为4.19.90。高版本将函数改名了。所以我在云服务器上跑了。
3.加载内核模块并查看模块打印信息
输出时间正确
4.卸载内核模块并查看模块打印信息
任务二:编写timer,在特定时刻打印 hello,world
时钟中断对于管理操作系统尤为重要,大量内核函数的生命周期都离不开流逝的时间的控制。正如我们所看到的,时钟中断能处理许多内核任务,所以它对内核来说极为重要。
定时器(有时也称为动态定时器或内核定时器)是管理内核流逝的时间的基础。内核经常需要推后执行某些代码,我们需要的是一种工具,能够使工作在指定时间点上执行——不长不短,正好在希望的时间点上。内核定时器正是解决这个问题的理想工具。
1.编写对应的源文件time_example.c 以及对应的Makefile
2. make 并查看编译后产生的文件
3.加载内核模块并查看模块打印信息
4.卸载内核模块并查看模块打印信息
代码中设置定时器超时时间为10*HZ(10秒),对应上图中模块加载后10秒才打印hello,world!。模块功能满足任务要求。
任务三:调用内核时钟接口,监控累加计算代码的运行时间
1.编写对应的源文件sum_time.c 以及对应的Makefile
2. make 并查看编译后产生的文件
3.加载内核模块并查看模块打印信息
4.卸载内核模块并查看模块打印信息
运行结果可以看出,从 1 到 100000 的累加和所花时间是1575 us。
实验六:设备管理
任务1:编写USB设备驱动程序
1.编写对应的源文件usb_detect.c 以及对应的Makefile
2. make 并查看编译后产生的文件
3.加载内核模块并查看模块打印信息
插入U盘
出现报错。不知道怎么解决。
去网上搜了一下,找到这样一篇回答。
然后在我的Makefile文件里面,加上了一句
lsusb 这里存在一个错误。
查找后发现是因为系统没有安装usbutils包造成的。
直接yum install usbutils,成功解决。
模块检测到U盘插入;并且获取到的U盘信息与lsusb显示的一致。
拔掉U盘 可以看到设备号为2 的设备已经断开连接。
lsusb也没有之前插入U盘的列表
4.卸载U盘检测模块
任务2:编写内核模块测试硬盘的读写速率,并与 iozone工具的测试结果比较
1.编写代码write_to_disk.c,read_from_disk.c分别用来测试硬盘读写速率。
编写相应的Makefile文件。
/usr/src/kernels/4.19.90-2003.4.0.0036.oe1.x86_64
报错,换华为云服务器做。
2. make 并查看编译后产生的文件
read
write
编译成功
3.加载内核模块并查看模块打印信息
额…这里搞迷糊了一下
我先加载read模块,报错。网上查了一下,可能是权限不够,或者文件不存在。
用sudo运行一样不行,看了一下路径/home/tmp_file,没有这个文件。
然后看了一下write…原来要先写入。。。
先运行write模块
根据打印的信息可以看到速度为894M/s
再加载read模块
4.卸载模块并查看文件信息
Write模块
改文件大小为512M
Read模块
5.iozone工具测试
(1)使用 free -m 查看当前内存大小,确保iozone命令中的 -g 参数设置的数值大于内存大小的两倍。
在本地虚拟机上执行make linux-AMD64产生错误
换到云服务器上
成功
执行./iozone -Raz -n 512m -g 8g -r 1k -i 0 -i 1 -b /home/iozone.xls
-a 全面测试,比如块大小它会自动加;
-r block size 制定一次写入/读出的块大小;
-s file size 制定测试文件的大小;
-f filename 制定测试文件的名字,完成后会自动删除;
-F file1 file2….. 多线程下测试的文件名;
-g –n 指定测试文件大小范围。-n 后接最小值,-g 后接最大值 ,如测试512m-4G:-n 512m –g 4G;
-y –q 指定测试块的大小范围;
-R 产生excel到标准输出;
-b 制定将结果输出到制定文件上,比如:-Rb test.xls;
通过得到的数据我们可以知道每次读写1kb块大小的文件
写入速率为66.36M/s
读速率为186.2M/s
实验七:文件系统
任务1:为 Ext4 文件系统添加扩展属性
文件扩展属性(xattr - Extended attributes)介绍
1、基本概念
文件扩展属性(xattr - Extended attributes)提供了一种机制,用来将key-value键值对永久地关联到文件;让现有的文件系统得以支持在原始设计中未提供的功能。扩展属性是目前流行的POSIX 文件系统具有的一项特殊的功能,可以给文件、文件夹添加额外的Key-value的键值对,键和值都是字符串并且有一定长度的限制——定义于include/uapi/linux/limits.h 文件中:
即:在保存xattr时, key的长度不能超过255byte,value 不能超过64k,总的配对数不能超过64k。
2、扩展属性名称空间
扩展属性名称的格式是namespace.attribute,名称空间namespace是用来定义不同的扩展属性的类。目前有security,system,trusted,user四种扩展属性类。
(1)扩展的安全属性-- security
安全属性名称空间被内核用于安全模块,例如SELinux。对安全属性的读和写权限依赖于策略的设定。这策略是由安全模块载入的。如果没有载入安全模块,所有的进程都对安全属性有读权限,写权限只有那些有CAP_SYS_ADMIN(允许执行系统管理任务,如加载或卸载文件系统、设置磁盘配额等)的进程才有。
(2)扩展的系统属性-- system
扩展的系统属性被内核用来存储系统对象,比如说ACL。对系统属性的读和写权限依赖于策略的设定。
(3)受信任的扩展属性-- trusted
受信任的扩展属性只对那些有CAP_SYS_ADMIN的进程可见和可获得。这个类中的属性被用来在用户空间中保存一些普通进程无法得到的信息。
(4)扩展的用户属性-- user
扩展的用户属性被分配给文件和目录用来存储任意的附加信息,比如mime type、字符集或是文件的编码。用户属性的权限由文件权限位来定义。对于普通文件和目录,文件权限位定义文件内容的访问,对于设备文件来说,它们定义对设备的访问。扩展的用户属性只被用于普通的文件和目录,对用户属性的访问被限定于属主和那些对目录有sticky位设置的用户。
3、文件系统特殊要求
对于ext文件系统,为了能使用扩展用户属性,要求文件系统挂载时有user_xattr选项。
在ext文件系统中,每一个扩展属性必须占用一个单独的文件系统块,块大小取决于创建文件系统时的设置。
1. 为了使用扩展属性,安装 libattr
2.检查当前文件系统是否支持文件扩展属性
(1)用 fdisk -l 查看硬盘及分区信息(本地)
(2)用 tune2fs -l 显示设备的详细信息
tune2fs命令允许系统管理员在ext2、ext3或ext4文件系统上调整各种可调的文件系统参数。这些选项的当前值可以使用-l选项显示。
该文件系统支持扩展用户属性user_xattr、与ACL权限。
3.使用setfattr设置EA,正确使用getfattr获取EA。
(1)对于不含转义字符 \ 的纯文本属性值,有无双引号限定效果一样。
(2)对于包含转义字符 \ 的文本属性值,无双引号则不对转义符 \ 进行转义;有双引号则对其进行转义。
例如:设置八进制数时,设置属性值为 \020 时,最终识别为文本020;设置属性值为“\020”时,最终以八进制数的base64编码存储。
(3)设置属性值为十六进制数时,所设置的数的位数必须为偶数,即0x 或 0X后的数字必须为偶数位,否则出错。 若设置成功,最终以十六进制数的base64编码存储。
(4)设置属性值为base64编码时,所设置的编码必须符合base64编码,即0s后的编码字符串必须符合base64编码,否则出错。 若设置成功,最终以base64编码对应的文本信息存储。
(5)使用getfattr获取属性后后进行text编码设置
当未对获取的属性进行编码设置时,直接使用 getfattr -d -m . file.txt 或 getfattr -d file.txt 即可完成
对获取的属性设置text编码时,结果如下:
可以看到user.age 属性值变成了对应的文本值
(6)使用getfattr获取属性后后进行hex编码设置。
均转换成16进制的值
(7)使用getfattr获取属性后后进行base64编码设置。
这些属性值都变为相对应的base64编码储存。
任务2:注册一个自定义的文件系统类型
通常,用户在为自己的系统编译内核时可以把linux配置为能够识别所有需要的文件系统。但是,文件系统的源代码实际上要么包含在内核映像中,要么作为一个模块被动态装入。VFS必须对目前已在内核中的所有文件系统类型进行跟踪。这就是通过进行文件系统类型注册来实现的。
1. 查看系统中已经注册的文件系统类型
cat /proc/filesystems
2.编写代码编写相应的Makefile文件。
3. make 并查看编译后产生的文件
4.加载模块查看已注册文件系统类型
可以看到当前系统中存在自定义文件系统“myfs”
5.卸载模块并查看已注册文件系统类型
当卸载内核模块时,当前系统中无自定义的文件系统“myfs”。
任务3:在/proc下创建目录
proc文件系统
Linux系统上的/proc目录是一种文件系统,即proc文件系统。与其它常见的文件系统不同的是,/proc是一种伪文件系统(也即虚拟文件系统),存储的是当前内核运行状态的一系列特殊文件,用户可以通过这些文件查看有关系统硬件及当前正在运行进程的信息,甚至可以通过更改其中某些文件来改变内核的运行状态。
基于 /proc文件系统如上所述的特殊性,其内的文件也常被称作虚拟文件,并具有一些独特的特点。例如,其中有些文件虽然使用查看命令查看时会返回大量信息,但文件本身的大小却会显示为0字节。此外,这些特殊文件中大多数文件的时间及日期属性通常为当前系统时间和日期,这跟它们随时会被刷新(存储于RAM中)有关。
为了查看及使用上的方便,这些文件通常会按照相关性进行分类存储于不同的目录甚至子目录中,如/proc/scsi目录中存储的就是当前系统上所有SCSI设备的相关信息,/proc/N中存储的则是系统当前正在运行的进程的相关信息,其中N为正在运行的进程PID(在某进程结束后其相关目录则会消失)。
大多数虚拟文件可以使用文件查看命令如cat、more或者less进行查看,有些文件信息表述的内容可以一目了然,但也有文件的信息却不怎么具有可读性。不过,这些可读性较差的文件在使用一些命令如apm、free、lspci或top查看时却可以有着不错的表现。
1.编写代码编写相应的Makefile文件。
2. make 并查看编译后产生的文件
3.加载模块
加载模块前/proc下无myproc目录
加载模块后/proc下可查找到proc目录
4.卸载模块
卸载模块后/proc下无myproc目录
/usr/src/kernels/5.10.0-5.10.0.24.oe1.x86_64
任务4:使用sysfs文件系统传递内核模块参数
sysfs文件系统
1、基本概念
内核子系统或设备驱动可以直接编译到内核,也可以编译成模块。如果编译到内核,可以通过内核启动参数来向它们传递参数;如果编译成模块,则可以通过命令行在插入模块时传递参数,或者在运行时,通过sysfs来设置或读取模块数据。
sysfs是一个基于内存的虚拟文件系统,可以看成与proc、devfs和devpty同类别的文件系统;它的作用是将内核信息以文件的方式提供给用户程序使用。sysfs 文件系统要求总是被挂载在 /sys 挂载点上,这个文件系统不仅可以把设备(devices)和驱动程序(drivers)的信息从内核输出到用户空间,也可以用来对设备和驱动程序做设置。
sysfs提供一种机制,使得可以显式地描述内核对象、对象属性及对象间关系。sysfs有两组接口,一组针对内核,用于将设备映射到文件系统中;另一组针对用户程序,用于读取或操作这些设备。下表述了内核中的sysfs要素及其在用户空间的表现:
sysfs在内核中的组成要素 | 在用户空间的显示 |
内核对象(kobject) | 目录 |
对象属性(attribute) | 文件 |
对象关系(relationship) | 链接(Symbolic Link) |
2、sysfs 与 sysctl区别
sysctl:是内核的一些控制参数,其目的是方便用户对内核的行为进行控制;
sysfs:仅仅是把内核的 kobject 对象的层次关系与属性开放给用户查看,因此 sysfs 的绝大部分是只读的,模块作为一个 kobject 也被出口到 sysfs,模块参数则是作为模块属性出口的,内核实现者为模块的使用提供了更灵活的方式,允许用户设置模块参数在 sysfs 的可见性并允许用户在编写模块时设置这些参数在 sysfs 下的访问权限,然后用户就可以通过sysfs 来查看和设置模块参数,从而使得用户能在模块运行时控制模块行为。
1.编写代码编写相应的Makefile文件。
2. make 并查看编译后产生的文件
3.加载模块
查看打印信息如下:
进行参数传递:
4.卸载模块
由截图可知:
当未加载内核模块时,当前系统中无自定义的内核模块“sysfs_exam”;
当加载内核模块时,当前系统可见自定义的文件系统“sysfs_exam”;
使用modinfo查看内核模块信息,可见a、b、c三个参数的描述:
parm: a:An invisible int under sysfs (int)
parm: b:An visible int under sysfs (int)
parm: c:An visible string under sysfs (charp)
即参数a在/sys中不可见,b、c在/sys中可见,ls -al /sys/module/sysfs_exam/parameters/的输出列表可验证;
可使用echo向模块传递参数值来改变指定参数的值。将c值从“Hello,World”改为“I am DS!”
实验八:网络管理
任务1:编写基于socket的udp发送接收程序
Socket 是做什么的?
socket起源于Unix,而Unix/Linux基本哲学之一就是“一切皆文件”,都可以用“打开open –> 读写write/read –> 关闭close”模式来操作。Socket就是该模式的一个实现,socket即是一种特殊的文件,一些socket函数就是对其进行的操作(读/写IO、打开、关闭).
简言之,socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在socket接口后面,对用户来说,一组简单的接口就是全部,让socket去组织数据,以符合指定的协议。
1.编写给予socket的udp客户端和服务端源码
2.gcc编译
3.在Xshell上开启另一个中端,一个运行客户端程序,另一个运行服务端程序。
客户端:
服务端:
任务2:使用 tshark 抓包
tshark简介
tshark是wireshark中提供的Linux命令行工具,tshark不仅有抓包的功能,还带了解析各种协议的能力。由于wireshark的运行需要GUI(图形用户界面,Graphical User Interface)的环境,但是树莓派openEuler系统的缺省安装是不含GUI的,此时就可以使用tshark进行抓包。
1.先安装wireshark
2.开启三个客户端,一个作为服务端,一个作为客户端。第三个进行抓包
客户端:
服务端:
抓包:
如图抓包成功。
任务3:使用 setsockopt 发送记录路由选项
客户端:
服务端:
在重定向的 setsockopt.xml 文件中,可看到如下记录路由内容:
实验九:内核虚拟化
任务一:
安装qemu sudo yum install qemu -y
安装虚拟化组件dnf install -y libvirt qemu
确认libvirt是否安装成功。
确认qemu是否安装成功。
启动libvirtd服务 systemctl start libvirtd
未报错
安装完libvirt后,libvirt会自动生成default虚拟网络virtbr0:
……不知道接下来该干嘛。
本地内核不支持…kvm
任务二:搭建和使用docker
一、docker简介
由于在操作系统中创建虚拟机,存在资源占用多、冗余步骤多、启动慢等缺点,Linux 发展出了另一种虚拟化技术:Linux 容器(LXC,Linux Containers)。Linux 容器不是模拟一个完整的操作系统,而是通过cgroup与系统其他部分隔离开的一系列进程。Linux 容器具有极佳的可移植性,但前提是它们必须与底层系统兼容。
Docker 属于 Linux 容器的一种封装,提供简单易用的容器使用接口;用户操作 Docker 的容器就像操作一个快速轻量级的虚拟机一样简单。它是目前最流行的 Linux 容器解决方案。相比虚拟机,具有:启动快、体积小、资源占用少等优势。
Docker管理的对象包含镜像、容器、网络、数据卷等。
1.安装docker yum install docker
2.启动docker
启动容器有两种方式:
一种是基于镜像新建一个容器并启动;
另外一个是将在终止状态(stopped)的容器重新启动。
(1)新建并启动
所需要的命令主要为 docker run。
格式为 RUN <command> 或 RUN ["executable", "param1", "param2"]。
前者将在 shell 终端中运行命令,即 /bin/sh -c;后者则使用 exec 执行。指定使用其它终端可以通过第二种方式实现,例如 RUN ["/bin/bash", "-c", "echo hello"]。
例如,下面的命令输出一个 “Hello World”,之后终止容器。
sudo docker run ubuntu:14.04 /bin/echo 'Hello world' |
这跟在本地直接执行 /bin/echo 'hello world' 几乎感觉不出任何区别。
这里下载了Ubuntu 14.04 的镜像。
当利用 docker run 来创建容器时,Docker 在后台运行的标准操作包括:
- 检查本地是否存在指定的镜像,不存在就从公有仓库下载;
- 利用镜像创建并启动一个容器;
- 分配一个文件系统,并在只读的镜像层外面挂载一层可读写层;
- 从宿主主机配置的网桥接口中桥接一个虚拟接口到容器中去;
- 从地址池配置一个 ip 地址给容器;
- 执行用户指定的应用程序;
- 执行完毕后容器被终止。
下面的命令则启动一个 bash 终端,允许用户进行交互;在交互模式下,用户可以通过所创建的终端来输入命令;输入exit可推出交互模式。
sudo docker run -it ubuntu:14.04 /bin/bash
说明:
-t 选项让Docker分配一个伪终端(pseudo-tty)并绑定到容器的标准输入上;
-i 则让容器的标准输入保持打开。
注:当创建容器的时候,系统默认会分配一个名字。使用 --name 标记可以为容器自定义命名(NAMES 可通过 docker ps -n N(N为数字,表示显示最后被创建的 n 个容器))。
测试一下:创建两个容器,命名为myfirst_docker,mysec_docker
成功!
(2)启动已终止容器
利用 docker start container_id 或 docker start NAMES命令,启动运行一个已经终止的容器。container_id 可通过 docker ps -n N(N为数字,表示显示最后被创建的 n 个容器)查看:
使用docker start container_id或 docker start NAMES可以再次执行一遍,通过docker logs container_id 可以看到执行docker start前后,打印“Hello world”数量的区别。
第一次运行docker logs 1e83f609271c 只有一个输出
使用docker start myfist_docker再次运行后,查看 变为两个输出,即再次执行了一次。
3. 守护态运行
使用 -d 参数可以让 Docker 容器在后台以守护态(Daemonized)形式运行。
测试如下:
查看输出信息
通过 docker logs container_id或 docker logs NAMES命令获取容器的输出信息:
4. 终止容器
使用 docker stop NAMES或docker stop container_id来终止一个运行中的容器。
5. 删除容器
使用 docker rm NAMES 或 docker rm container_id来删除一个处于终止状态的容器。
可以在下图中看到,删除成功。
编写Dockerfile并创建镜像
编写Dockerfile
使用命令 docker image build -t helloworld_ubuntu .创建镜像
启动容器,输出Hello world!
ISula
使用iSulad运行容器
安装iSulad:yum install -y iSulad
将iSulad的原始配置文件备份:
cp /etc/isulad/daemon.json /etc/isulad/daemon.json.origin
打开iSulad的配置文件,修改容器镜像仓库的配置参数,执行指令如下:
vim /etc/isulad/daemon.json
按图所示修改
安装JSON格式数据处理工具:yum install -y jq
重新启动iSulad服务,执行命令如下:systemctl restart isulad
执行以下命令查看iSulad服务启动状态:systemctl status isulad
查询后q退出
iSula运行容器的使用
创建容器openeuler:20.09:
isula create -it openeuler/openeuler:20.09
创建成功:
isula ps -a 查看所有容器
运行容器,获取容器内部信息。
获取容器信息方式有两种:
1.使用容器ID。该方法需先启动容器然后读取容器内部信息,启动容器命令示例如下:
isula start "CONTANINER ID"
以下命令打印容器中的os-release文件信息:
isula exec "CONTANINER ID" cat /etc/os-release
结果如下图:
2.使用镜像名称。
使用run命令直接运行容器并输出:
isula run openeuler/openeuler:20.09 cat /etc/os-release
在run命令的基础上添加-it参数可以进入容器中的交互式终端,在容器中进行操作,命令如下:
isula run -it openeuler/openeuler:20.09
为确认当前环境是否是容器,执行以下命令打印容器镜像版本并退出容器:
cat /etc/os-release; exit
此时再次执行打印容器镜像版本命令:
cat /etc/os-release
两次输出结果进行对比,发现容器内的系统版本为openEuler 20.09,而退出容器后的系统版本为弹性云服务器的系统版本openEuler 20.03,表示确实登录到了容器环境。对比图如下所示:
iSula停止及清理
使用isula除可运行容器外,也可暂停运行中的容器内所有进程。
首先查看运行中的容器列表,执行命令如下:
isula ps
暂停容器进程命令示例如下:
注意:请使用查询到的容器ID(可以只使用容器ID的前几位)替换掉命令中的”CONTANINER ID”
isula pause "CONTAINER ID"
此时再次执行查看容器列表命令:
isula ps
发现容器的状态由“Up”变为“Paused”
恢复容器进程命令如下示例:
注意:请使用查询到的容器ID(可以只使用容器ID的前几位)替换掉命令中的”CONTANINER ID”
isula unpause "CONTAINER ID"
再次执行查看容器列表命令:
isula ps
发现容器的状态又恢复为正常的运行状态
整体过程如下图所示:
删除容器需要先将其停止,执行命令如下:
isula stop "CONTAINER ID"
使用删除命令删除该容器:
isula rm "CONTAINER ID"
返回容器ID表明容器被正确删除,如下图所示:
删除镜像:
在删除镜像前需要将容器全部删除,指令如下:
isula rm -f $(isula ps -aq)
执行以下命令查看所有容器:
isula ps -a
此时容器列表为空,所有容器都已删除
清理完容器后可删除镜像,执行如下命令查看镜像:
isula images
删除镜像:isula rmi openeuler/openeuler:20.09
结果如下:
构建容器镜像
iSula提供了容器镜像构建工具isula-build,安装命令如下:
yum --enablerepo update install -y isula-build
执行以下命令,确认isula-build服务是否启动:
systemctl status isula-build
isula-build未启动;
使用命令 systemctl start isula-build启动
成功启动。
isula-build构建Dockerfile内的RUN指令时依赖可执行文件runc,需要执行以下命令在isula-build的运行环境上预装好 runc:
yum install -y docker-runc
构建镜像导入到iSulad
Dockerfile是包含一系列命令的用于构建容器镜像的配置文件,构建镜像需先创建Dockerfile配置文件。执行以下命令,创建一个测试目录并进入:
mkdir isula- test && cd isula-test
执行以下命令编辑Dockerfile文件:
vim Dockerfile
在文件中输入以下内容:
说明:FROM命令为以该镜像为基础镜像构建镜像;COPY命令为拷贝构建目录下的hello.sh文件到镜像的/usr/bin目录;CMD为镜像容器启动后运行的入口命令执行hello.sh脚本。
为hello.sh脚本文件添加可执行权限以能够直接运行该文件,命令如下:
chmod +x hello.sh
构建容器镜像hello-isula-build:v0.1的执行命令如下:
说明:ctr-img子命令包含全部容器镜像管理命令,其中的build子命令为容器镜像构建,-f参数用于指定Dockerfile文件,并使用-o参数导出构建的镜像到isulad容器引擎,最后的“.”表示构建所使用的目录为当前目录。
isula-build ctr-img build -f Dockerfile -o isulad:hello-isula-build:v0.1 .
执行成功如下图所示:
查询构建镜像的命令如下:isula-build ctr-img images
结果如下:
由于构建命令中指定镜像导出到iSulad中,使用isula命令同样可以查询到该镜像,执行命令如下:isula images
结果:
执行以下命令运行构建的镜像:isula run hello-isula-build:v0.1
镜像构建无误并执行成功如下图所示:
A-Tune
安装A-Tune
yum install atune -y
yum install atune-engine -y
验证是否安装成功。
安装成功。
部署A-Tune
A-Tune配置文件/etc/atuned/atuned.cnf
修改network为对应的网卡
A-Tune engine配置文件/etc/atuned/engine.cnf
启动A-Tune
systemctl start atuned
systemctl status atuned
启动A-Tune engine
systemctl start atune-engine
systemctl status atune-engine
atune-adm命令
列出系统当前支持的profile,以及当前处于active状态的profile。
运行示例:atune-adm list
profile命令
激活profile,使其处于active状态。
接口语法:atune-adm profile
运行示例:激活big-data-hadoop-spark-wordcount对应的profile配置
atune-adm profile big-data-hadoop-spark-wordcount
系统信息查询 check
功能:检查系统当前的cpu、bios、os、网卡等信息。
命令格式atune-adm check
使用示例