Docker网络模式与cgroups资源控制
目录
1.docker网络模式原理
2.端口映射
3.Docker网络模式(4+1种)
1.查看docker网络列表
2.网络模式详解
4.Docker cgroups资源控制
1.CPU资源控制
2.对内存使用的限制
3.对磁盘IO的配置控制(blkio)的限制
4.清除docker占用的磁盘空间
总结
1.对cpu的限制参数
2.对内存的限制
3.对磁盘IO的限制
1.docker网络模式原理
docker 使用linux 桥接,在宿主机虚拟一个docker 容器网桥(docker0) ,docker 启动一个容器时会根据docker 网桥的网段分配给容器一个IP地址,称为Container-IP,同时Docker 网桥是每个容器的默认网关。因为在同一宿主机内的容器都接入同一个网桥,这样容器之间就能够通过容器的 Container-IP 直接通信。
       docker 网桥是宿主机虚拟出来的,并不是真实存在的网络设备,外部网络是无法寻址到的,这也意味着外部网络无法直接通过Container-IP 访问到容器。如果容器希望外部访问能够访问到,可以通过映射容器端口到宿主机(端口映射),即 docker run 创建容器时候,通过 -p 或者 -P 参数来启用。访问容器的时候,就通过 [宿主机IP]:[映射端口] 访问容器。
  
2.端口映射
法一
#随机映射端口(从32768开始)
docker run -d --name 为容器指定名称 -P 镜像名称法二
#自定义映射端口
docker run -d --name 为容器指定名称 -p 宿主机端口:容器端口 镜像名称 
法一:

 
法二:
 
验证结果

查看端口

3.Docker网络模式(4+1种)
(1)Host: 容器不会虚拟出自己的网卡,配置主机的IP等,而是使用宿主机的IP和端口
 (2)Container: 创建的容器不会创建自己的网卡,配置自己的IP,而是和一个指定的容器共享IP,端口范围
 (3)None: 该模式关闭了容器的网络功能。
 (4)Bridge: 默认为该模式,此模式会为每一个容器分配,设置IP等,并将容器连接到一个docker0 的虚拟网桥,通过docker 0 网桥以及iptables nat 表配置与宿主机通信。
 (5)自定义网络
 安装Docker 时,它会自动创建三个网络:bridge(创建容器默认连接到此网络)、none、host。
  
1.查看docker网络列表
docker network ls 或 docker network list   
 

使用docker run 创建Docker容器时可以使用--net或--network选项指定容器的网络模式
host模式:使用--net=host指定none模式:使用--net=none指定container模式:使用--net=container:NAME或者ID指定bridge模式:使用--net+bridge指定,默认设置可省略 
 
2.网络模式详解
1.host模式
       1. 相当于Vmware中的桥接模式,与宿主机在同一个网络中,但没有独立IP地址。
2.Docker使用了Linux的Namespaces技术来进行资源隔离,如PTD Namespace隔离进程,Mount Namespace隔离文件系统,Network Namespace隔离网络等。
3.一个Network Namespace提供了一份独立的网络环境,包括网卡、路由、iptable规则等都与其他的Network Namespace隔离。
      4.一个Docker容器一般会分配一个独立的Network Namespace。但如果启动容器的时候使用host模式,那么这个容器将不会获得一个独立的Network Namespace,而是和宿主机共用一个Network Namespace。容器将不会虚拟出自己的网卡、配置白己的IP等,而是使用宿主机的IP和端口。
2.container模式
在理解了host模式后,这个模式也就好理解了。这个模式指定新创建的容器和已经存在的一个容器共享一个Network Namespace,而不是和宿主机共享。新创建的容器不会创建自己的网卡,配置自己的IP,而是和一个指定的容器共享IP、端口范围等。同样,两个容器除了网络方面,其他的如文件系统、进程列表等还是隔离的。两个容器的进程可以通过lo网卡设备通信。

查看容器的pid号
docker inspect -f '{{.State.Pid}}' 容器名或ID 
查看命名空间编号
ls -l /proc/PID号/ns 

 
3.none模式
     1.使用none 模式,docker 容器有自己的network Namespace ,但是并不为Docker 容器进行任何网络配置。也就是说,这个Docker 容器没有网卡,ip, 路由等信息。
       2.这种网络模式下,容器只有lo 回环网络,没有其他网卡。
       3.这种类型没有办法联网,但是封闭的网络能很好的保证容器的安全性。
       4.该容器将完全独立于网络,用户可以根据需要为容器添加网卡。此模式拥有所有端口。(none网络模式配置网络
       5.特殊情况下才会用到,一般不用。
  

4.bridge 模式
      1.相当于Vmware中的 nat 模式,容器使用独立network Namespace,并连接到docker0虚拟网卡。通过docker0网桥以及iptables nat表配置与宿主机通信,此模式会为每一个容器分配Network Namespace、设置IP等,并将一个主机上的 Docker 容器连接到一个虚拟网桥上。
        2.当Docker进程启动时,会在主机上创建一个名为docker0的虚拟网桥,此主机上启动的Docker容器会连接到这个虚拟网桥上。虚拟网桥的工作方式和物理交换机类似,这样主机上的所有容器就通过交换机连在了一个二层网络中。
         3.从docker0子网中分配一个IP给容器使用,并设置docker0的IP地址为容器的默认网关。在主机上创建一对虚拟网卡veth pair设备。veth设备总是成对出现的,它们组成了一个数据的通道,数据从一个设备进入,就会从另一个设备出来。因此,veth设备常用来连接两个网络设备。
          4.Docker将veth pair 设备的一端放在新创建的容器中,并命名为eth0(容器的网卡),另一端放在主机中, 以veth*这样类似的名字命名,并将这个网络设备加入到docker0网桥中。可以通过 brctl show 命令查看。
          5.使用 docker run -p 时,docker实际是在iptables做了DNAT规则,实现端口转发功能。可以使用iptables -t nat -vnL 查看。
docker inspect  test3 | grep -i 'networkmode' 

5.自定义网络
直接使用bridge 模式,还是无法指定IP运行docker
ifcongfig
#直接使用bridge模式,是无法支持指定IP运行docker的,例如执行以下命令就会报错
docker run -id --name test4 --network bridge --ip 172.17.0.1 centos:7 
bash 

创建自定义网络
//创建自定义网络
#可以先自定义网络,再使用指定IP运行docker 
docker network create --subnet=172.18.0.0/16 --opt "com.docker.network.bridge.name"="docker1" mynetwork
------------------#docker1为执行ifconfig -a命令时,显示的网卡名,使用--opt参数指定名称#mynetwork 为执行 docker network list 命令时,显示的bridge网络模式名称。
------------------docker run -itd --name test8 --network mynetwork --ip 172.18.0.10 nginx:latest /bin/bash
docker inspect test5 |grep IPAddress
#查看ip地址 

4.Docker cgroups资源控制
1.CPU资源控制
cgroups,是一个非常强大的linux内核工具,他不仅可以限制被namespace隔离起来的资源,还可以为资源设置权、计算使用量、操控进程启停等等。所以cgroups(Control groups)实现了对资源的配额和度量。
1.cgroups四大功能
(1)资源限制:可以对任务使用的资源总额进行限制;
(2)优先级分配:通过分配的cpu时间片数量以及磁盘IO带宽大小,实际上相当于控制了任务运行优先级;
(3)资源统计:可以统计系统的资源使用量,如cpu时长,内存用量等;
(4)任务控制:cgroup可以对任务执行挂起、恢复等操作。
2.设置CPU使用率上限
  (1)Linux通过CFS(Completely Fair scheduler,完全公平调度器)来调度各个进程对CPU的使用。CFS默认的调度周期是100ms。
   (2)我们可以设置每个容器进程的调度周期,以及在这个周期内各个容器最多能使用多少CPU时间。
   (3)使用--cpu-period 即可设置调度周期,使用--cpu-quota即可设置在每个周期内容器能使用的CPU时间。两者可以配合使用。CFS周期的有效范围是1ms~1s,对应的--cpu-period 的数值范围是1000~1000000(微秒)。
  (4)容器的CPU配额必须不小于1ms,即--cpu-quota的值必须>=1000。
  
查看容器默认CPU使用限制
docker run -itd --name c1 centos:7 /bin/bash
cd /sys/fs/cgroup/cpu/docker/
ls
cd 4f2ffa469e17d8b6e1e2d6c356363b8c9710204748abc769a4fcbd303d74f71f/
cat cpu.cfs_quota_us
----------------------
-1
cat cpu.cfs_period_us
------------
100000 

 
进行压力测试
docker exec -it c1 bash 
vi /cpu.sh
------------------------
#!/bin/bash
i=0
while true
dolet i++
done
------------------------
chmod +x cpu.sh  #给脚本权限
./cpu.sh         #运行脚本top             #查看cpu使用率 

 
另一个终端查看CPU使用率

停止运行脚本

再查看cpu使用率

创建容器时设置CPU使用时间限制
docker run -itd --name test2 --cpu-quota 50000 centos:7
cd /sys/fs/cgroup/cpu/docker/
ls
cd a8c9e47344cb7b98579340f0b05361d9c789dcbcb6160e7874445eec5950bd4e/
cat cpu.cfs_quota_us
---------------------------
50000 最高限额为设置的50000 

编写脚本进行测试
docker exec -it test2 bash
vi /cpu.sh
--------------------------
#!/bin/bash
i=0
while true
dolet i++
done
--------------------------
chmod +x cpu.sh
./cpu.sh   #执行脚本 

 
容器的CPU使用时间限制设为50000,而调度周期为100000,表示容器占用50000/100000=50%的CPU

对已存在的容器进行CPU限制
直接修改/sys/fs/cgroup/cpu/docker/容器id/cpu.cfs_quota_us文件即可
 
cd /sys/fs/cgroup/cpu/docker/
ls
cd 4f2ffa469e17d8b6e1e2d6c356363b8c9710204748abc769a4fcbd303d74f71f/
ls
echo "33000" >cpu.cfs_quota_us
cat cpu.cfs_quota_us 
#进入c1容器
docker exec -it c1 bash 
./cpu.sh  #执行刚才创建的脚本 
 

3.设置cpu资源占用比(设置多个容器时才有效)
Docker 通过--cpu-shares指定CPU份额,默认值为1024,值为1024的倍数
#创建两个容器为t1和t2,若只有这两个容器,设置容器的权重,使得c1和c2的CPU资源占比为1/3和2/3。
docker run -itd --name t1 --cpu-shares 512 centos:7
docker run -itd --name t2 --cpu-shares 1024 centos:7 

#进入容器t1,进行压力测试
docker exec -it t1 bash
yum install -y epel-release   #安装在线源
yum install -y stress         #安装检测软件
stress -c4   #产生四个进程,每个进程都反复不停的计算随机数的平方根#进入容器t2,进行压力测试
docker exec -it t2 bash
yum install -y epel-release   #安装在线源
yum install -y stress         #安装检测软件
stress -c 4   #产生四个进程,每个进程都反复不停的计算随机数的平方根 
容器t1

 
 
容器t2

 

#查看容器运行状态(动态更新)
docker stats 

4.设置容器绑定指定的CPU

#先分配虚拟机4个CPU核数
docker run -itd --name c3 --cpuset-cpus 1,3 centos:7 /bin/bash
#--cpuset-cpus:指定绑定核数可以是多个
#注意这里的核号是从0开始 指定的1,3代表第二个核和第四个核yum install -y epel-release
yum install stress -y 
stress -c 4 
 
 另一个终端输入top后按1 

2.对内存使用的限制
1.限制容器可以使用的最大内存
-m(--memory=):用于限制容器可以使用的最大内存
 
docker run -itd --name c4 -m 512m centos:7 /bin/bashdocker stats 

2.限制容器可用的swap 大小
 限制可用的swap 大小,--memory-swap强调一下, --memory-swap是必须要与 --memory(或-m)一起使用的。正常情况下, --memory-swap 的值包含容器可用内存和可用swap 。所以 -m 300m --memory-swap=1g 的含义为:容器可以使用300M 的物理内存,并且可以使用700M (1G - 300M)的swap。如果 --memory-swap 的值设置为0或者不设置,则容器可以使用的 swap 大小为 -m 值的两倍。如果 --memory-swap 的值和 -m 值相同,则容器不能使用swap。如果 --memory-swap 值为 -1,它表示容器程序使用的内存受限,而可以使用的swap空间使用不受限制(宿主机有多少swap 容器就可以使用多少)。 
 
3.对磁盘IO的配置控制(blkio)的限制
 --device-read-bps:限制某个设备上的读速度bps ( 数据量),单位可以是kb、mb (M)或者gb。例: docker run -itd --name test9 --device-read-bps /dev/sda:1M centos:7 /bin/bash#表示该容器每秒只能读取1M的数据量--device-write-bps : 限制某个设备上的写速度bps ( 数据量),单位可以是kb、mb (M)或者gb。例: docker run -itd --name test10 --device-write-bps /dev/sda:1mb centos:7 /bin/bash#表示该容器每秒只能写入1M的数据量--device-read-iops :限制读某个设备的iops (次数)--device-write-iops :限制写入某个设备的iops ( 次数) 
1.创建容器,不限制写速度
 #创建容器tt01,不限制写入速度docker run -it --name t3 centos:7 /bin/bash#通过dd来验证写速度,拷贝50M的数据dd if=/dev/zero of=/opt/test.out bs=10M count=5 oflag=direct   #添加oflag参数以规避掉文件系统cache 

2.创建容器,并限制写速度
#创建容器,并限制写入速度为1MB/s,即每秒只能写入1MB的数据量。
docker run -it --name t2 --device-write-bps /dev/sda:1mb centos:7 bash
#通过dd来验证写速度,拷贝50M的数据到容器中
dd if=/dev/zero of=/opt/test.out bs=10M count=5 oflag=direct  #添加oflag参数以规避掉文件系统cache 

4.清除docker占用的磁盘空间
docker system prune -a 可用于清理磁盘,删除关闭的容器、无用的数据卷和网络。 
示例:
#查看容器
docker ps -a
#清理磁盘,删除关闭的容器、无用的数据卷和网络。
docker system prune -a
#再次查看容器,只剩下启动中的容器
docker ps -a 

留下运行中的容器

总结
1.对cpu的限制参数
 docker run -cpu-period     #设置调度周期时间1000~1000000-cpu-quota      #设置容器进程的CPU占用时间,要与调度周期时间成比例--cpu-shares    #设置多个容器之间的CPU资源占用比--cpuset-cpus   #绑核(第一个CPU编号从0开始) 
2.对内存的限制
 -m 物理内存 [--memory-swap=总值]
 
3.对磁盘IO的限制
 --device-read-bps 设备文件:1mb/1M     #限制读速度--device-write-bps 设备文件:1mb/1M    #限制写速度--device-read-iops                   #限制读次数--device-write-iops                  #限制写次数docker system prune -a             #释放无用的资源 
 
 
 
 
相关文章:
Docker网络模式与cgroups资源控制
目录 1.docker网络模式原理 2.端口映射 3.Docker网络模式(41种) 1.查看docker网络列表 2.网络模式详解 4.Docker cgroups资源控制 1.CPU资源控制 2.对内存使用的限制 3.对磁盘IO的配置控制(blkio)的限制 4.清除docker占用…...
Linux/C++:基于TCP协议实现网络版本计算器(自定义应用层协议)
目录 Sock.hpp TcpServer.hpp Protocol.hpp CalServer.cc CalClient.cc 分析 因为,TCP面向字节流,所以TCP有粘包问题,故我们需要应用层协议来区分每一个数据包。防止读取到半个,一个半数据包的情况。 Sock.hpp #pragma on…...
并发之阻塞队列
阻塞队列 使用背景作用从阻塞队列中获取元素常用的三个方法往阻塞队列中存放元素的三种方式 使用背景 想要在多个线程之间传递数据,用一般的对象是不行的,比如我们常用的ArrayList和HashMap都不适合由多个线程同时操作,可能会造成数据丢失或…...
nodejs+vue 智能餐厅菜品厨位分配管理系统
系统功能主要介绍以下几点: 本智能餐厅管理系统主要包括三大功能模块,即用户功能模块和管理员功能模块、厨房功能模块。 (1)管理员模块:系统中的核心用户是管理员,管理员登录后,通过管理员功能来…...
MySQL NULL 值
NULL 值是遗漏的未知数据,默认地,表的列可以存放 NULL 值。 本章讲解 IS NULL 和 IS NOT NULL 操作符。 如果表中的某个列是可选的,那么我们可以在不向该列添加值的情况下插入新记录或更新已有的记录。这意味着该字段将以 NULL 值保存。 N…...
Python 机器人学习手册:1~5
原文:ILearning Robotics using Python 协议:CC BY-NC-SA 4.0 译者:飞龙 本文来自【ApacheCN 计算机视觉 译文集】,采用译后编辑(MTPE)流程来尽可能提升效率。 当别人说你没有底线的时候,你最好…...
OpenCV(14)-OpenCV4.0中文文档学习2(补充)
相机校准和3D重建 相机校准 标定 findChessboardCorners() 它返回角点和阈值,如果成功找到所有角点,则返回 True。这些角落将按顺序放置(从左到右,从上到下)cornerSubPix()用以寻找图案,找到角点后也可以…...
八、express框架解析
文章目录 前言一、express 路由简介1、定义2、基础使用 二、express 获取参数1、获取请求报文参数2、获取路由参数 三、express 响应设置1、一般响应设置2、其他响应设置 四、express 防盗链五、express 路由模块化1、模块中代码如下:2、主文件中代码如下࿱…...
SpringBoot整合接口管理工具Swagger
Swagger Swagger简介 Springboot整合swagger Swagger 常用注解 一、Swagger简介  Swagger 是一系列 RESTful API 的工具,通过 Swagger 可以获得项目的⼀种交互式文档,客户端 SDK 的自动生成等功能。  Swagger 的目标是为 REST APIs 定义一个标…...
50+常用工具函数之xijs更新指南(v1.2.3)
xijs 是一款开箱即用的 js 业务工具库, 聚集于解决业务中遇到的常用的js函数问题, 帮助开发者更高效的进行业务开发. 目前已聚合了50常用工具函数, 接下来就和大家一起分享一下v1.2.3 版本的更新内容. 1. 添加将树结构转换成扁平数组方法 该模块主要由 EasyRo 贡献, 添加内容如…...
【DAY42】vue学习
const routes [ { path: ‘/foo’, component: Foo }, { path: ‘/bar’, component: Bar } ]定义路由的作用是什么 const routes 定义路由的作用是将每一个 URL 请求映射到一个组件,其中 path 表示请求的 URL,component 表示对应的组件。 通过 const…...
JavaScript小记——事件
HTML 事件是发生在 HTML 元素上的事情。 当在 HTML 页面中使用 JavaScript 时, JavaScript 可以触发这些事件。 Html事件 HTML 事件可以是浏览器行为,也可以是用户行为。 以下是 HTML 事件的实例: HTML 页面完成加载HTML input 字段改变…...
Windows逆向安全(一)之基础知识(八)
if else嵌套 这次来研究if else嵌套在汇编中的表现形式,本次以获取三个数中最大的数这个函数为例子,分析if else的汇编形式 求三个数中的最大值 首先贴上代码: #include "stdafx.h"int result0; int getMax(int i,int j,int k)…...
PyCharm+PyQt5+pyinstaller打包labelImg.exe
0 开头 labelImg是一款标注软件,作为一个开源项目,它的源码可以在github上找到。官方仓库地址为: https://github.com/heartexlabs/labelImg 小白安装时的最新版本编译出来的界面长这样: 之前在小白的博客里,也教过…...
JavaScript里实现继承的几种方式
JavaScript 中的继承可以通过以下几种方式来实现: 1、原型链继承:通过将子类的原型对象指向父类的实例来实现继承。这种方式的优点是实现简单,缺点是父类的私有属性和方法子类是不能访问的。 function Parent() {this.name parent;this.ag…...
前端:运用HTML+CSS+JavaScript实现迷宫游戏
最近感到挺无聊的,于是想到了大学期间关于栈的应用知识,于是就写了这篇博客! 运用HTML+CSS+JavaScript实现迷宫游戏 1. 运行结果2. 实现思路3. 参考代码1. 运行结果 前端:做个迷宫玩玩,不会迷路吧! 2. 实现思路 如果有一个迷宫,有入口,也有出口,那么怎样找到从入口到出…...
NoSQL数据库简介
NoSQL代表“不仅是SQL”,指的是一种数据库管理系统,旨在处理大量非结构化和半结构化数据。与使用具有预定义架构的表格格式的传统SQL数据库不同,NoSQL数据库是无模式的,并且允许灵活和动态的数据结构。 NoSQL数据库是必需的&…...
面试马铭泽
为什么报考这个岗位 首先,我对军人从小有崇敬之情,梦想着穿着庄严的军装,更对祖国有强烈的热爱之心。我的大舅是一名现役军人,老舅也曾服过兵役,从他们的谈吐以及教育中,让我对部队一直充满向往之情&#…...
查看AWS S3的目录
要查看AWS S3存储桶(Bucket)的目录,您可以通过AWS管理控制台或AWS CLI(命令行界面)来实现。 在AWS管理控制台中查看: 登录AWS管理控制台。选择S3服务。在S3存储桶列表中选择要查看的存储桶。在对象列表中…...
分布式系统概念和设计-操作系统中的支持和设计
分布式系统概念和设计 操作系统支持 中间件和底层操作系统的关系,操作系统如何满足中间件需求。 中间件需求:访问物理资源的效率和健壮性,多种资源管理策略的灵活性。 任何一个操作系统的目标都是提供一个在物理层(处理器,内存&a…...
未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?
编辑:陈萍萍的公主一点人工一点智能 未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战,在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…...
C++初阶-list的底层
目录 1.std::list实现的所有代码 2.list的简单介绍 2.1实现list的类 2.2_list_iterator的实现 2.2.1_list_iterator实现的原因和好处 2.2.2_list_iterator实现 2.3_list_node的实现 2.3.1. 避免递归的模板依赖 2.3.2. 内存布局一致性 2.3.3. 类型安全的替代方案 2.3.…...
中南大学无人机智能体的全面评估!BEDI:用于评估无人机上具身智能体的综合性基准测试
作者:Mingning Guo, Mengwei Wu, Jiarun He, Shaoxian Li, Haifeng Li, Chao Tao单位:中南大学地球科学与信息物理学院论文标题:BEDI: A Comprehensive Benchmark for Evaluating Embodied Agents on UAVs论文链接:https://arxiv.…...
cf2117E
原题链接:https://codeforces.com/contest/2117/problem/E 题目背景: 给定两个数组a,b,可以执行多次以下操作:选择 i (1 < i < n - 1),并设置 或,也可以在执行上述操作前执行一次删除任意 和 。求…...
CocosCreator 之 JavaScript/TypeScript和Java的相互交互
引擎版本: 3.8.1 语言: JavaScript/TypeScript、C、Java 环境:Window 参考:Java原生反射机制 您好,我是鹤九日! 回顾 在上篇文章中:CocosCreator Android项目接入UnityAds 广告SDK。 我们简单讲…...
拉力测试cuda pytorch 把 4070显卡拉满
import torch import timedef stress_test_gpu(matrix_size16384, duration300):"""对GPU进行压力测试,通过持续的矩阵乘法来最大化GPU利用率参数:matrix_size: 矩阵维度大小,增大可提高计算复杂度duration: 测试持续时间(秒&…...
深入解析C++中的extern关键字:跨文件共享变量与函数的终极指南
🚀 C extern 关键字深度解析:跨文件编程的终极指南 📅 更新时间:2025年6月5日 🏷️ 标签:C | extern关键字 | 多文件编程 | 链接与声明 | 现代C 文章目录 前言🔥一、extern 是什么?&…...
Angular微前端架构:Module Federation + ngx-build-plus (Webpack)
以下是一个完整的 Angular 微前端示例,其中使用的是 Module Federation 和 npx-build-plus 实现了主应用(Shell)与子应用(Remote)的集成。 🛠️ 项目结构 angular-mf/ ├── shell-app/ # 主应用&…...
【7色560页】职场可视化逻辑图高级数据分析PPT模版
7种色调职场工作汇报PPT,橙蓝、黑红、红蓝、蓝橙灰、浅蓝、浅绿、深蓝七种色调模版 【7色560页】职场可视化逻辑图高级数据分析PPT模版:职场可视化逻辑图分析PPT模版https://pan.quark.cn/s/78aeabbd92d1...
Selenium常用函数介绍
目录 一,元素定位 1.1 cssSeector 1.2 xpath 二,操作测试对象 三,窗口 3.1 案例 3.2 窗口切换 3.3 窗口大小 3.4 屏幕截图 3.5 关闭窗口 四,弹窗 五,等待 六,导航 七,文件上传 …...
