当前位置:   article > 正文

22-06-25 西安 linux(02) 命令、shell脚本开发、linux安装软件_netstat -anp |grep 端口号

netstat -anp |grep 端口号

进程相关命令

Process:进程是CPU进行资源分配的基本单元,每一个应用程序至少包含一个进程(也可以包含多个进程)

Thread:线程是cpu执行的基本单元,一个进程至少包含一个线程(也可以包含多个线程)

1、ps -ef

ps -ef   以完整格式查看全部进程

e对应单词entire,表示全部,具体指显示系统中全部的进程信息

f对应单词ful-formate,表示完整格式

进程信息各列的说明

列名含义
UID进程的用户信息
PID当前进程的id,每一个进程都有的唯一的id。由系统分配,不会重复。
PPID父进程的id。你这个进程是谁启动的就是父进程。
CMD当前进程所对应的程序。
C用整数表示的CPU使用率
STIME进程启动时间
TTY进程所在终端。所谓终端就是用户输入命令的操作界面。
TIME进程所占用的CPU时间

父进程和子进程之间的关系

父进程和子进程的关系是:父进程启动了子进程。我们可以使用pstree命令查看整个进程树

和其它命令配合一起查看进程信息

ps -ef | less  分屏查看全部进程
ps -ef | grep ssh  精确查询一个具体进程信息

最后一个是是grep命令本身 ,怎么排除呢,再用一层管道,使用grep命令的-v参数把匹配grep的行排除

ps -ef | grep ssh | grep -v grep 


2、aux

aux 查看系统中所有的进程

ps aux | grep xxx 查看系统中所有的进程

a 列出带有终端的所有用户的进程

x 列出当前用户的所有进程,包括没有终端的进程

u 面向用户友好的显示风格


3、netstat查看端口占用

显示网络状态和端口号占用信息

netstat -anp | grep 进程号 查看该进程网络信息

netstat -nlp | grep 端口号 查看网络端口号占用情况

-n 拒绝显示别名,能显示数字的全部转化为数字

-l 仅列出在Listen(监听)的服务状态

-p 显示建立相关链接的程序名


4、lsof

lsof -i:6379   遍历所有文件,找下6379端口被占用的文件

  1. lsof = list of file --->lsof
  2. -i = interface接口--->端口

grep和lsof区别

没启动redis之前

启动redis之后


5、结束进程

为什么要结束进程?(非正常关闭)

因为采用正常关闭已经做不了了,我不知道怎么去关闭一个进程了,这时候才杀进程

但是一般不推荐杀死进程,原因举例:杀进程,临时文件不会被删除。

kill -9 进程id  表示杀死指定id的进程


系统运维

top

类似于windows任务管理器的性能面板

命令名更新时间间隔(秒)不显示任何闲置或者僵死进程通过进程id监控单一进程
top-d 间隔秒数-i-p 进程id

上图红色框圈住俩部分,上面那一部分:整个系统的健康状态

第一行:任务队列信息

内容举例说明
09:55:40系统当前时间
up 8:50系统的运行时间
2 users当前登录了2个用户
load average:0.00, 0.05, 0.07系统在之前1分钟,5分钟,15分钟的平均负载。 一般认为小于1时,负载较小。如果大于1,系统已经超出负荷。

第二行:进程信息

内容举例说明
Tasks: 198 total系统中的进程总数
1 running正在运行的进程数
197 sleeping睡眠的进程
0 stopped正在停止的进程
0 zombie僵尸进程。如果不是0,需要手工检查僵尸进程

第三行:CPU信息

内容举例说明
Cpu(s):0.1%us用户空间占用的CPU百分比,us对应user
0.1%sy内核空间占用的CPU百分比,sy对应system
0.0%ni改变过优先级的进程占用的CPU百分比,ni对应niced
99.7%id空闲CPU的CPU百分比
0.1%wa等待输入/输出的进程的占用CPU百分比,wa对应IO wait
0.0%hi硬中断请求服务占用的CPU百分比,hi对应hardware IRQ
0.1%si软中断请求服务占用的CPU百分比,si对应software IRQ
0.0%stst(Steal time)虚拟时间百分比,也叫被hypervisor偷走的时间。 就是当有虚拟机时,虚拟CPU等待实际CPU的时间百分比。

第四行:物理内存信息

内容举例说明
997980 total物理内存的总量,单位KB
61296 free空闲的物理内存数量
514552 used已经使用的物理内存数量
422132 buff/cache作为缓冲的内存数量

第五行:交换区使用情况

内容举例说明
2097148 total交换分区(虚拟内存)的总大小
1789704 free空闲交换分区的大小
307444 used已经使用的交互分区的大小
277064 avail Mem在不交换的情况下,对启动新应用程序可用内存的估计

上图中两个红框,下面这部分:就是进程信息了,可以通过按键操作按照不同条件排序,比如我按了“N”,就按照pid排序了

----------

可以有的按键操作

按键功能
P默认值,根据CPU使用率排序
M以内存的使用率排序
N以PID排序
d设置数据刷新的时间间隔,单位是秒
q退出

网络状态命令

查看虚拟机ip       ifconfig

netstat命令是查看网络状态,常用参数列表如下:

参数名作用
-a显示所有正在或不在侦听的套接字。
-n显示数字形式地址而不是去解析主机、端口或用户名。
-p显示套接字所属进程的PID和名称。

为什么要去查看网络状态,大部分时侯是去查询谁占用了某个端口

netstat -anp

第一部分:tcp/udp 与外部服务器建立的连接
第二部分:linux 内部应用之间的连接 

netstat -anp | less  分屏查看网络状态


netstat -anp | grep sshd  根据进程名称查看网络状态

netstat -anp | grep :22 根据端口号查看网络状态,找谁占用22端口


字符串处理的命令

basename 获取一个资源中的资源名部分,文件或目录本身部分

usr/local/aa/bb/cc.txt 真正的资源是cc.txt
usr/local/aa/bb/cc 获取的是cc

dirname(和basename 相反) 返回路径字符串中的目录部分

dirname /usr/local/aa/bb/cc

dirname /usr/local/aa/bb/cc.txt


cut 切割文件 
根据指定符号拆分字符串并提取。默认根据 \t 拆分 (默认制表符) 

  • -f 参数:指定要提取的列
  • -d 参数:指定拆分依据的字符

cut -f 1 cut.txt     拿第一列
cut -f 2-  cut.txt    拿第二列,及以后的列

cut切割变量值
ifconfig | grep netmask,怎么通过切割只获取ip的值呢

 ifconfig | grep netmask | cut -d 'i' -f 2,这样就能把前面的空白符去掉了

 再按空格切分获取第二列就好了,管道是一个很实用的技术


sort 文件排序
将文件进行排序,并将排序结果标准输出。

参数名作用
-n依照数值大小排序
-r相反顺序排序
-t指定每列分割符
-k指定需要排序的列

sort -t  '  ' -k 2 sort.txt


Linux权限管理

只有拥有权限的用户才能操作这些资源。

专业术语
1.用户(登录系统的账户密码,用户的身份标识)
2.登录(专业说法是认证)
3.资源 (这个系统的所有内容,无论文件还是目录,资源是权限控制系统要保护的对象 )
4.授权(系统给用户分配权限)
5.校验(当用户操作某个资源的时候,系统会校验用户是否有权限)
6.用户组(同一类用户归类到同一个组)

用户:一个账号和密码
用户组:多个用户
只要给用户组授权,那么每一个用户就都授权了。

创建用户和用户组的命令(只能root做)

命令作用
groupadd 组名创建用户组
id 用户名查看用户信息
useradd -g 组名 用户名创建用户,同时指定所属用户组
passwd 用户名给用户账号设置密码



创建用户不指定组,会创建一个新组,组名就是用户名


文件权限

1. 文件权限信息说明

资源所属用户   资源所属用户组
 root                root

文件权限就是最前面那10个字符,如下图 drwxr-xr-x

第一个字符:表示当前资源类型 d是目录,l是连接,-是文件
后九个字符:表示当前资源的权限

后九个字符又分为:

前三个字符:资源拥有者的权限
中间三个字符:资源拥有组里用户的权限
后三个字符:其它组的用户的权限

每三个字符中又可能包含

r(read): 
如果资源是一个文件,那么有r权限代表可以使用cat、more、less、tail、vim命令查看文件

如果资源是一个目录,那么有r权限代表可以使用ls、ll命令列出目录中的内容

w(write):
如果资源是一个文件,那么有w权限代表可以可以使用vim命令编辑文件

如果资源是一个目录,那么有w权限代表可以在该目录中使用mkdir、touch、rm、rmdir,mv等等命令创建、删除、攻变资源

x (execut):
如果资源是一个文件,那么有x权限代表可以直接执行这个文件(可执行文件);]
如果资源是一个目录,那么有x权限代表可以使用cd命令进入这个目录

-:无权限

由于每一位要么有权限要么没有权限,所以天然可以使用二进制来表示权限信息,即可以用十进制表示权限。

  • 1:有

  • 0:无

权限的符号表示权限的二进制表示权限的十进制表示
rwx r-x r-x111 101 1017 5 5
rw- r-- r--110 100 1006 4 4

2、修改文件权限

目标:让tom能在/opt目录中新建内容

命令名作用
chmod修改权限信息
chown修改文件或目录的所属用户
chgrp修改文件或目录的所属用户组

方式一:让tom成为/opt目录的拥有者(只有root可以改)

  • chown tom /opt 修改拥有者
  • chgrp atguigu /opt 修改拥有组
  • chown root:root /opt 同时修改拥有者和拥有组

方式二:修改资源的权限

精准修改资源的权限
chmod u=rwx,g=rx,o=rwx  /opt

其中u表示拥有者,g表示同组用户,o表示其它用户

chmod 755 /opt

这三位数字分别表示: 拥有者的权限、同组用户的权限、其它用户的权限

r:是4; w:是2;x:是1

提升普通用户的权限

方式三:让tom变得跟root-一样牛皮!!
提升普通用户的权限(sudo)

为什么root那么牛皮?
vim /etc/sudoers,改这个文件
Allow root to run any commands anywhere
Allows people in group wheel to run all commands

得亮尚方宝剑
sudo rmdir xixi


Linux系统服务管理

计算机中,一个正在执行的程序或命令,被叫做“进程”;启动后一直存在、常驻内存的进程,一般被称做“服务”。

查看centos版本

cat /etc/redhat-release

service服务管理(centos 6版本)

基本语法:service 服务名 start/stop/restart/status

服务名后面加一个d,代表当前进程是一个守护进程

  1. 之后我是用过这个的,因为端口占用问题:
  2. service mysqld stop

操作系统中在后台持续运行的程序,本身并没有操作界面,需要通过端口号访问和操作
启动、停止、查看状态、重启、设置开机自启动,停止开机自启动

systemctl (centos 7版本)

启动服务:systemctl start 服务名(xxxx.service)
重启服务:systemctl restart 服务名(xxxx.service)
停止服务:systemctl stop 服务名(xxxx.service)
重新加载服务:systemctl reload 服务名(xxxx.service)
查看服务状态:systemctl status 服务名(xxxx.service) 

设置开机自动启动:systemctl enable 服务名

取消开机自动启动:systemctl disable 服务名

====

查看服务的方法

ls /usr/lib/systemd/system

systemctl status firewalld 查看防火墙状态


查看服务状态列表(root)
1、systemctl list-unit-files 查所有服务

2、查看mysql服务是否启动


linux里面的防火墙

防火墙的作用是啥:拦截外部访问

防火墙拦截外部访问的机制:
1.基于白名单:只有在白名单中的路径才不拦截
2.基于黑名单:只有在黑名单中的路径才拦截


防火墙端口设置:

基于白名单

firewall-cmd --zone=public --list-ports  查看所有放行的端口号

firewall-cmd --zone=public --query-port=22/tcp  查看某个端口是否放行

firewall-cmd --add-port=3306/tcp --permanent  防火墙开放端口

firewall-cmd --reload 更新防火墙规则

firewall-cmd --remove-port=端口/tcp --permanent  防火墙取消端口开放

学习阶段:
关闭防火墙 systemctl stop firewalld
设置开机不自启动 systemctl disable firewalld 

查看防火墙开机时是否启动  systemctl list-unit-files | grep firewalld

常用端口

  • 8080 tomcat

  • 80 http协议

  • 443 https协议

  • 22 ssh远程连接

  • 3306 mysql

  • 6379 redis


Shell脚本开发

做某一件事情:需要执行10行Linux命令,而我们又要经常做这件事情。我们将这10行命令编写到一个.sh结尾的文件中,到时候要做这件事情了,就只需要执行那个.sh结尾的文件。这种.sh结尾的文件叫Shell脚本,而编写.sh结尾的文件的过程就叫做Shell编程!

Shell是一个命令行解释器,它接收应用程序或用户的命令,然后调用操作系统内核。 它是一个功能强大的编程语言,易编写、易调试、灵活性强

Shell解释器:解释执行Shell脚本的

js也是脚本语言,js解释器内置在浏览器 。

Linux系统提供的Shell解析器,其中最常用的是 /bin/sh 和 /bin/bash。sh是bash的软链接,Linux默认使用的是bash


1、shell脚本的运行命令

1.使用touch创建脚本文件,以.sh作为扩展名

2.编写脚本内容,使用vim jade.sh

3.运行脚本

其中“.”是source的另一种写法。在当前进程中发布的全局变量可以在当前进程的其他脚本中继续沿用,也可以在子进程中使用;但是子进程发布的变量仅限于子进程内部使用

命令名在当前进程运行新建子进程运行
source
.
sh
bash
chmod +x后直接运行

 老师使用多的是 sh,向老师看齐


2、预定义、自定义变量、特殊变量

shell系统预定义变量
$PATH,$USER、$HOME、$PWD、$SHELL等,可以使用echo命令输出他们的值

 执行文件:


Shell自定义变量

 语法规则

  • 变量名称可以由字母、数字和下划线组成,但是不能以数字开头,环境变量名建议大写。

  • 等号两侧不能有空格,衍生规则就是变量声明时必须初始化

  • 在bash中,变量默认类型都是字符串类型,无法直接进行数值运算。

  • 变量的值如果有空格,需要使用双引号或单引号括起来。

  • 变量名区分大小写。

 变量名=变量值

执行文件: 

静态变量(只读变量),就得加上readonly

自定义的变量还可以使用unset命令进行撤销(让变量失效),但是静态变量无法撤销

unset username


特殊变量

$0 表示获取执行的脚本的名称
$1-$n  表示获取用户执行脚本时传入的第1个到第n个参数,
从${10}开始数字需要使用{}括起来

$# 表示获取用户执行脚本时传入的参数个数
$? 表示获取上一句命令的执行结果
如果上一句命令执行结果是boolean值则true为0 false为1
如果上一句执行结果不是boolean类型,那么执行成功为0,执行失败为非零

$*和$@都是获取用户执行脚本时传入的所有参数,只有在循环中且放在引号中能够体现出它们的区别。下面会说到!


3、运算表达式

Shell中运算表达式写法:  $((表达式))或$[表达式] 

142857,又名走马灯数。它发现于埃及金字塔内,它是一组神奇的数字,细思则恐的数字


4、条件判断

常用判断条件:

数据类型写法单词含义
数值-ltless than小于
数值-leless equal小于等于
数值-eqequal等于
数值-gtgreater than大于
数值-gegreater equal大于等于
数值-nenot equal不等于
文件-rread判断当前用户是否可以读取该文件
文件-wwrite判断当前用户是否可以修改该文件
文件-xexecute判断当前用户对该文件是否有执行权限
文件-ffile判断是否存在并且必须是文件
文件-eexistence判断目录或者文件是否存在
文件-ddirectory判断是否存在并且是一个目录

判断表达式的俩种写法

test condition
[ condition ]


5、流程控制

三元运算符:判断表达式 && true || false
判断表达式连接符表达式为true的时候执行的代码
连接符表达式为false的时候执行的代码


if语句

4.1 单if

 vim shell.sh    #编辑我们的测试shell脚本的文件

  1. #!/bin/bash
  2. if test 10 -gt 5
  3. then
  4. echo "10大于5"
  5. fi

4.2 if -else

  1. #!/bin/bash
  2. if test 10 -gt 5
  3. then
  4. echo "10大于5"
  5. else
  6. echo "10小于5"
  7. fi

4.3 if elif -else

  1. if [ 10 -gt 5 ]
  2. then
  3. echo "10大于5"
  4. elif [ 10 -lt 5 ]
  5. then
  6. echo "10小于5"
  7. else
  8. echo "10等于5"
  9. fi

case判断

  1. #!/bin/bash
  2. couple=0
  3. case $couple in
  4. "0")
  5. echo "老婆"
  6. ;;
  7. "1")
  8. echo "媳妇"
  9. ;;
  10. *)
  11. echo "亲爱的"
  12. ;;
  13. esac

结果打印:


for 循环
1、打印1-4

  1. #!/bin/bash
  2. for ((i=1; i<=4;i++))
  3. do
  4. echo $i
  5. done

测试结果如下,要是你不在i前面加$,则打印结果是4个i

2、for in 循环,遍历集合

使用for in循环遍历出用户执行脚本时传入的每一个参数

  1. #!/bin/bash
  2. for i in $*
  3. do
  4. echo $i
  5. done


$@和$*的区别:

在不加引号的时候,俩者效果一样。加了引号之后, "$*"会将所有元素当成一个值处理,"$@"将所有元素每一个都遍历一次进行处理。


while 循环
求1-100累加和

  1. #!/bin/bash
  2. sum=0
  3. start=1
  4. while test $start -le 100
  5. do
  6. #累加
  7. sum=$[$sum+$start]
  8. #start的值自增1
  9. start=$[$start+1]
  10. done
  11. echo $sum

运行结果:


6、函数

在一个Shell脚本中会出现重复代码->函数
Shell 编程中要求函数的返回值只能是整数。并且只能通过 $? 方式获得。

shell中的函数可以显示加:return 返回,

如果不加,将以最后一条命令运行结果(这个运算结果可以表示true或者false,以及执行成功或者执行失败),作为返回值。return 后跟数值 n(0-255)。

  1. #!/bin/bash
  2. #函数声明
  3. function sum(){
  4. #在函数内部$1表示获取调用函数时传入的第一个参数
  5. return $[$1+$2]
  6. }
  7. # 调用函数,传入参数
  8. sum 99 100
  9. # 使用$?获取函数执行结果
  10. echo "sum 99 100执行的结果是$?"


7、获取脚本外部数

脚本内部代码不能完全写死,
所以我们要在脚本内部获取脚本外部传入的数据

获取外部参数的方式一:

前面说过了,通过$1、$2、……方式获取,从${10}开始需要使用大括号。

获取外部参数的方式二:

使用read读取用户的输入。类似于java中的scanner

read 命令的俩个常用参数

  • -t用于指定输入等待时间,单位是秒

  • -p用于指定提示文字

  1. read -t 10 -p "please enter:" NAME
  2. echo $NAME

服务器端应用程序的安装

1、虚拟机备份

备份配置文件

在修改任何配置文件之前都多复制一份:把原始、纯净、正确的配置文件执行了备份。将来万一发生问题,拿原始配置文件覆盖错误配置文件

虚拟机备份,通过快照恢复

为了避免安装失败以后没有退路可以重新开始,建议在执行相关安装之前拍摄快照。一旦发生问题,可以恢复快照重新开始。

创建快照:

恢复快照:

删除快照


2、安装jdk

查询系统中已经安装的jdk

rpm -qa | grep openjdk

安装jdk

yum -y install java-1.8.0-openjdk*

配置JDK环境变量

使用vi命令打开 /etc/profile

vim /etc/profile

下面内容添加到文件末尾 , 配置JAVA HOME

  1. export JAVA_HOME=/usr/lib/jvm/java-1.8.0
  2. export PATH=$PATH:$JAVA_HOME/bin

修改之后使其生效

保存退出vim后,使用source命令执行/etc/profile脚本,让脚本中发布的环境变量生效。

source /etc/profile

查看安装情况

java -version

3、安装tomcat

cd /opt,进入/opt目录,把tomcat的压缩包从物理机拽过来

解压就是

tar -zxvf /opt/apache-tomcat-8.5.32.tar.gz

启动tomcat   

/opt/apache-tomcat-8.5.32/bin/startup.sh

在物理机上访问tomcat,在 Windows 系统访问 Linux 服务器端的 Tomcat 需要使用 LInux 的 IP 地址,并且要保证防火墙关闭,或者放行了8080端口

查看tomcat日志信息   

tail -F /opt/apache-tomcat-8.5.32/logs/catalina.out

停止 tomcat

/opt/apache-tomcat-8.5.32/bin/shutdown.sh

如果要部署项目,将部署 war 包放在 webapps 目录下(这一步不一定要去做)

/opt/apache-tomcat-8.5.32/webapps


4、安装mysql

安装mysql之前一定要拍快照.

mariadb 和mysql的关系

MySQL 被 Oracle 收购,社区担心将来 MySQL 被 Oracle 关闭开源模式,和 Oracle 数据库一样变成商业化运作。所以社区开发了一个 MySQL 的社区版,内部和 MySQL 一样,只是名字不同,这就是 mariadb。

卸载系统预装 mariadb

1.查询系统中预装的mariadb

rpm -qa | grep mariadb --color

2.删除系统中预装的mariadb(如果第一步没查到就不删)

rpm -e --nodeps mariadb-libs-5.5.56-2.el7.x86_64

1.在虚拟机中的/usr/local中创建一个mysql目录

mkdir /usr/local/mysql

2.将mysql压缩包拷贝到/usr/local/mysql目录中,解压mysql的tar包

cd /usr/local/mysql
tar -zxvf mysql-5.7.25-1.el7.x86_64.rpm-bundle.tar.gz

3 安装MySQL,下述步骤依次执行

中间会停下来,按回车键就好

rpm -ivh mysql-community-common-5.7.25-1.el7.x86_64.rpm
rpm -ivh mysql-community-libs-5.7.25-1.el7.x86_64.rpm
rpm -ivh mysql-community-devel-5.7.25-1.el7.x86_64.rpm
rpm -ivh mysql-community-libs-compat-5.7.25-1.el7.x86_64.rpm
rpm -ivh mysql-community-client-5.7.25-1.el7.x86_64.rpm
rpm -ivh mysql-community-server-5.7.25-1.el7.x86_64.rpm

4. 修改MySQL的字符集配置

mysql默认使用的字符集是latin1,即:iso-8859-1,是不支持中文的。

要想让MySql支持中文,需要通过配置文件设置指定MySql使用utf-8字符集才可以。

修改MySql的字符集:

使用vim打开mysql的配置文件: vim /etc/my.cnf

进入编辑模式o,在[mysqld]下边添加内容:character-set-server=utf8

5.启动MySQL服务

systemctl start mysqld

6 设置MySQL服务开机自启动

systemctl enable mysqld

7.查看MySQL初始密码

安装MySQL的过程中会自动生成初始密码,我们可以在/var/log/mysqld.log文件中进行查看

cat /var/log/mysqld.log | grep "temporary password" --color

8.使用初始密码登录MySQL

p和初始密码之间千万不能空格

mysql -uroot -p'初始密码'

9.修改root的密码

在使用初始密码登录mysql之后,依次执行下面三行命令

set global validate_password_length=4;
set global validate_password_policy=LOW;
set password = password('root');

第一次修改密码一定要按照上述三步来做,修改完之后你如果想将密码改成其它的密码,你可以在退出mysql之后执行(需要在未登录mysql的情况下执行):exit是退出客户端,不是服务器

mysqladmin -uroot -p password 新密码  -- 新密码不需要加上引号


在物理机上使用sqlyog远程连接虚拟机上的MySQL

会遇到的问题:

1 .被防火墙拦截

解决方案是关闭防火墙或者是让防火墙放行3306端口

关闭防火墙命令

systemctl stop firewalld.service

放行3306端口的操作:

firewall-cmd --add-port=3306/tcp --permanent
# 放行端口后一定要重新加载防火墙配置
firewall-cmd --reload

问题2:MySQL服务器不允许远程访问

解决方案是让root用户能够远程访问MySQL服务器:

mysql默认不允许远程访问
mysql数据库-user表-放的是登录mysql的用户信息

host字段,表示当前这个用户能在什么客户端进行登录,
如果值为localhost表示只能本机登录
如果值为%表示可以远程登录。

# 允许远程访问:创建一个新的root对象,并且指定这个root对象对所有数据库里面的所有表都有所有权限,并且指定这个root用户的密码是123456
grant all on *.* to 'root'@'%' identified by '123456';
# 刷新设置
flush privileges;

解决上述俩问题之后,就可以使用宿主机中的SQLYog远程连接访问虚拟机中的MySQL了


设置开机自启动

1、zipkin+sentinel+mycat

2、nacos开机自启

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/633418
推荐阅读
相关标签
  

闽ICP备14008679号