软件安装:RPM、SRPM、YUM

《鸟哥的Linux私房菜》笔记




软件管理器简介

不是每个人都会进行源码安装的!

厂商先在他们的系统上面编译好了我们用户所需要的软件,然后将这个编译好的可执行的软件直接发布给用户安装。

如果在安装的时候还可以加上一些与这些程序有关的信息,将它新建成为数据库,那么就可以进行安装、反安装、升级与验证等的相关功能(类似Windows下的添加,删除程序)。在Linux上面有两种常见的软件管理器,分别是RH的rpm与Debian的dpkg。


Linux界的两大主流:RPM与DPKG

Linux开发商先在固定的硬件平台与操作系统平台上面将需要安装或升级的软件编译好,然后将软件的所有相关文件打包成为一个特殊格式的文件,在这个软件文件内还包含了预先检测系统与依赖软件的脚本,并提供记载该软件提供的所有文件信息等,最终将这个软件文件发布。

用户取得这个文件后,只要通过特定的指令来安装,那么该软件文件就会依照内部的脚本来检测相依的前驱软件是否存在。若安装的环境符合要求,那就会开始安装,安装完成后还会将该软件的信息写入软件管理机制中,以完成未来可以进行升级、删除等操作。

目前Linux界软件安装最常见的两种方式:

dpkg:这个机制最早是由Debian Linux社区开发出来的,由Debian衍生的其他Linux distribution大多使用dpkg这个机制来管理软件;

rpm:这个机制最早是由Red Hat这家公司开发出来的,因为很好用,所以很多distribution就使用这个机制来作为软件安装的管理方式;

不论是dpkg还是rpm,这些机制都会有软件依赖性的问题,那么该如何解决呢?每个软件文件都有提供依赖性检查,如果我们将依赖性的信息做成列表,等到软件实际安装时,若发生有依赖性的软件问题时,透过依赖属性列表,管理机制自动去安装依赖,不就解决了依赖性的问题了吗!

目前Linux开发商提供了这样的“在线升级”机制,只有有网络,你就能够取得原本开发商提供的任何软件。

Linux系统在线升级机制


什么是RPM与SRPM

RPM全名是“RedHat Package Manager”,简称为RPM。当初这个软件管理机制是由Red Hat这家公司发展出来的。RPM是以一种数据库记录的方式来将你所需要的软件安装到你的Linux系统的一套管理机制。

它最大的特点就是将你要安装的软件先编译过,并且打包成为RPM机制的包装文件,透过包装好的软件里面默认的数据库记录,记录这个软件要安装的时候必须具备的依赖性软件。当安装在你的Linux主机时,RPM会先依照软件里面的信息查询Linux主机的依赖属性是否满足,若满足则予以安装,不满足则不予安装。安装的时候就将该软件的信息整个写入RPM的数据库中,以便未来的查询、验证与反安装!优点:

由于已经编译完成并且打包完毕,所以软件传输与安装上很方便(无需重新编译);

由于软件的信息都已经记录在Linux主机的数据库上,很方便查询、升级与反安装。


但这也造成些许困扰。由于RPM文件是已经包装好的数据,也就是说,里面的数据都已经“编译完成”了。所以,该软件几乎只能安装在原本默认的硬件与操作系统版本中。也就是说,你的主机系统环境必须要与当初建立这个软件数据的主机环境相同才行。强制安装通常会发生一些错误!这些 软件管理机制的问题是:

软件文件安装的环境必须与打包时的环境一致或相当;

需要满足软件的依赖性需求;

反安装时需要特别小心,最底层的软件不可先移除,否则可能造成整个系统的问题!


如果我真的想要安装其他distribution提供的好用的RPM软件数据,那就得利用SRPM这个东西!SRPM,它是Source RPM的意思,也就是这个RPM文件里面含有源码,但注意,这个SRPM提供的软件内容并没有经过编译,它提供的是源码。


通常SRPM文件扩展名为***.src.rpm。

与Tarball比对:SRPM虽然内容是源码,但它仍然含有该软件所需要的依赖性说明以及所有RPM文件所提供的资料;

与RPM对比:它提供了参数配置文件(configure与makefile)。


如果我们下载的是SRPM文件,那么在安装时,必须要:

先将该软件以RPM管理的方式编译,此时SRPM会被编译成RPM文件;

然后将编译完成的RPM文件安装到Linux系统中。


通常一个软件发布的时候,都会同时发布该软件的RPM与SRPM。我们可以通过修改SRPM内的参数配置文件,然后重新编译产生能适合我们Linux环境的RPM文件。如此一来,就可以将软件安装到我们的系统当中,而不必与原厂商打包的Linux环境相同了。

rpm与srpm


什么是i386,i586,i686,noarch,x86_64

gcc-4.8.5-11.el7.x86_64

#gcc 软件名称;

#4.8.5 版本信息;

#11 是发布版本次数;

#el7.x86_64 是操作硬件平台;

由于RPM可以适用于不同的操作平台上,但是不同的平台设置的参数还是有所差异!我们可以针对比较高级的CPU来进行最佳化参数的设置,这样才能使用高级CPU所带来的硬件加速功能。所以就有所谓的i386,i586,i686,x86_64与noarch等的文件名出现了。


各个平台及平台说明

由于x86系统的支援,新的CPU都能够执行老旧CPU所支持的软件,也就是说硬件方面是可以向下兼容的,因此最低等级的i386软件也可以安装在所有的x86硬件平台上面,无论32位还是64位。


RPM的优点

rpm内包含已经编译过的程序与配置文件等资料,可以让使用者免除重新编译的困扰;

rpm在被安装之前会先检查系统的硬盘容量、操作系统版本等,可以避免文件被错误安装;

rpm文件本身提供软件版本信息,依赖性软件名称、软件用途说明、软件所包含文件等信息,便于了解软件;

rpm管理的方式使用数据库记录RPM文件的相关参数,便于升级、移除、查询与验证。


为了解决软件之间依赖性问题,rpm在提供打包的软件时,同时加入一些信息登录的功能,这些信息包括软件的版本、软件打包者、依赖的其他软件、本软件的功能说明、本软件的所有文件记录等等,然后在Linux系统上面也建立一个rpm软件数据库。如此一来,当你要安装某个以rpm类型提供的软件时,在安装过程中,rpm回去检验一下数据库里面是否已经存在相关的软件。如果数据库显示不存在,那么这个rpm文件默认就不能安装。这就是rpm类型文件为人诟病的软件依赖性问题!


rpm依赖性的克服方式:yum在线升级

rpm软件文件内部会记录依赖性的资料,要是我将这些依赖性的软件先列表,在有安装软件需求的时候,先到这个列表去找,同时与系统内已经安装的软件相比较,没安装到的依赖软件就一口气同时安装起来了,那样就解决了依赖性问题了。这就是yum机制的由来。

yum使用示意图

软件仓库内的清单会记载每个文件的依赖性关系,以及所有文件的URL。

当用户端有升级、安装的需求时,yum会向软件仓库要求清单的更新,等到清单更新到本机的/var/cache/yum里面后,等一下更新时就会用这个本机清单与本机的rpm数据库进行比较,这样就知道该下载什么软件。接下来yum会跑到软件仓库服务器(yum server)下载所需要的软件,然后再通过rpm的机制开始安装软件啦!



RPM软件管理程序:rpm

RPM的使用不难,只要使用rpm这个命令即可。

rpm -q    #查询已安装的软件

#rpm现在主要是用来查询与检验软件,安装通过yum就可以了!


RPM默认安装的路径

RPM文件安装完毕后,该软件相关信息会被写入/var/lib/rpm/目录下的数据库中。这个目录内的信息很重要,因为未来如果我们有任何软件升级的需求,版本之间的比较就是来自于这个数据库,而且你想要查询系统已经安装的软件也是从这里查询的!这个目录主要不要被删了!

几个目录的意义


RPM安装(install)

因为安装软件是root的工作,需要是root才能够操作rpm命令。

rpm命令

rpm -ivh /home/zhang/aaa.rpm    ;

rpm -ivh aaa.rpm bbb.rpm    #安装多个软件;

rpm -ivh http://www.xxx.com/path/ccc.rpm    #安装网络上的么某个文件。


如果我们在安装的过程中发现问题(如缺少依赖),或者已经知道会发生的问题,但还是要执意安装此软件。可以使用如下参数“强制”安装软件:

rpm安装时常用的选项与参数说明

尽量不要通过“暴力安装”,可能会发生很多不可预期的问题。


RPM升级与更新(upgrade/freshen)

-U, --upgrade=+    升级软件包;

-F, --freshen=+    如果软件包已经安装,升级软件包。


首先需要下载新版本的rpm包;

使用更新-F 或 -U将系统的软件更新。

从上看来,如果是大量升级旧版本软件,使用-Fvh是比较好的办法。当然,升级也是可以利用--nodeps或--force等参数。不过现在有了yum机制,就不需要上面这些方法了!


RPM查询(query)

RPM在查询的时候,是查询/var/lib/rpm这个目录下的数据库文件。另外,RPM也可以查询未安装的RPM文件内的信息!

rpm -q

查询已安装到系统上面的软件信息,这部分由/var/lib/rpm/提供;

查询某个rpm文件内容,等于是由RPM文件内找出一些要写入数据库内的信息就是了,使用 -qp;

查询本机上面的rpm软件相关信息时,不需要加上版本的名称,只要软件名即可!


RPM验证与数字签名(Verify/signature)

验证(Verify)的功能主要是在于提供给系统管理员一个有用的管理机制!使用/var/lib/rpm/下的数据库内容来比对目前Linux系统的环境下的所有软件信息。

使用简单的方法验证原来的文件系统,好让你了解修改了哪些文件资料。

-V :后面加的是软体名称,若该软体所含的档案被更动过,才会列出来;

-Va :列出目前系统上面所有可能被更动过的档案;

-Vp :后面加的是档案名称,列出该软体内可能被更动过的档案;

-Vf :列出某个档案是否被更动过~

rpm -V文件


文件前面有几个字母,他们的意思为:

S :(file Size differs) 档案的容量大小是否被改变;

M :(Mode differs) 档案的类型或档案的属性(rwx) 是否被改变?如是否可执行等参数已被改变;

5 :(MD5 sum differs) MD5 这一种指纹码的内容已经不同;

D :(Device major/minor number mis-match) 装置的主/次代码已经改变;

L :(readLink(2) path mis-match) Link 路径已被改变;

U :(User ownership differs) 档案的所属人已被改变;

T :(mTime differs) 档案的建立时间已被改变;

P :(caPabilities differ) 功能已经被改变。


文件类型有以下几类:

c :配置文件(config file);

d :文件资料档(documentation);

g :鬼文件~通常是该档案不被某个软体所包含,较少发生!(ghost file);

l :授权文件(license file);

r :只读文件(read me)。


数字签名(digital signature)

验证只能验证软件内的信息与/var/lib/rpm/里面的数据库信息而已,如果该软件文件本身就有问题,那使用验证的手段也无法确定该软件的正确性啊!我们可以通过数字签名来检验软件的来源。

就像你自己的签名一样,我们的软件开发商发布的软件也会有一个厂商自己的签名系统!只是这个签名被数字化了。厂商可以利用数字签名系统产生一个专属该软件的签名,并将公钥(public key)放出。

首先你必须要先安装原厂发布的公钥文件;

实际安装原厂的RPM软件时,rpm指令会去读取RPM文件的签名信息,与本及系统内的签名信息比对;

若签名相同则予以安装,若找不到相关的签名信息时,则给予警告并停止安装。

Centos使用的数字签名系统为GNU计划的GnuPG.

Centos数字签名位于:

数字签名只是一堆乱码


rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7    #安装

find /etc -name '*GPG-KEY*'    #查找GPG密钥文件位置


这串乱码是数字签名非常重要的一环


RPM反安装与重建数据库(erase/rebuilddb)

反安装就是将软件解除安装,要注意,解安装的过程一定是由最上层往下层解除。解除A软件之前先得解除B软件。

rpm -e xxx    #当然也可以加入--nodeps参数强制移除

由于RPM文件常常会安装/移除/升级,某些动作可能导致RPM数据库/var/lib/rpm/内的文件受损。

rpm --rebuilddb    #重建rpm数据库



YUM在线升级机制

yum就是通过分析RPM的列表头资料后,根据各软件的相关性制作出依赖性的解决方案,然后自动处理依赖性软件问题,以解决软件安装或移除与升级的问题。

由于distribution必须要先发布软件,然后将软件放置到yum服务器上,以提供给用户端来要求安装与升级。因此我们想要使用yum的功能时,必须要先找到适合的yum server才行,每个yum server可能都会提供许多个不同的软件功能,那就是“软件仓库”。因此,你必须要前往yum server查询到相关的软件仓库网址后,再继续处理后续的设定事宜!


利用yum进行查询、安装、升级与移除功能

查询功能:yum [list | info | search | provides | whatprovides]参数

yum [option] [查询工作项目] [相关参数]

选项与参数:

[option]:主要的选项有:

-y:自动提供yes回答;

--installroot=/some/path:将该软件安装在/some/path下,而不是用默认路径;

[查询工作项目][相关参数]有:

search:搜寻某个软件名称或描述的重要关键字;

list:列出目前yum所管理的所有软件名称与版本,类似rpm -qa;

info:类似rpm -qai;

provides:从文件去查找软件,类似rpm -qf。


升级/安装功能:yum [install | update]软件

yum

yum install自动解决依赖性问题!


移除软件:yum remove 软件

yum remove 软件名

虽然yum特别简单,但也是架构在rpm上面所发展起来的,所以还是需要了解rpm才行。


yum的设置文件

虽然yum 是主机连上Internet就可以用,不过,由于Centos映射的站台可能会选错。

举个栗子,我们中国,可能映射到日本,美国等的服务器,这样的速度是非常慢的。所以我们可以手动修改yum的设置文件,自定义yum服务器。

yum设置文件


最重要的就是 “repodata” 的目录!该目录就是分析RPM软件后所产生的软件属性依赖资料存放处!因此,当你要找软件仓库所在的网址时,最重要的就是该网址下面一定要有一个名为repodata的目录存在,那就是软件仓库的网址了!

修改软件仓库文件


需要注意的几个是:

[base]    #代表软件仓库的名字!中括号[]一定要存在,里面的名称则可以随意取,但不能有两个相同的仓库名,否则yum会不晓得该到哪里去找相关软件清单文件;

name    #只是说明这个软件库的意义而已,重要性不搞;

mirrorlist    #列出这个软件仓库可以使用的映射网址,如果不想使用可以注释掉;

baseurl    #这个最重要,这个后面接的是软件库的实际网址;

enable=1    #让这个软件被启动;

gpgcheck=1    #这个就是前面的RPM数字签名;

gpgkey=    #这儿接数字签名公钥文件所在的位置。


修改软件仓库产生的问题与解决之道:

由于我们是修改系统默认的设置文件,事实上,我们应该在/etc/yum.repos.d/下面新建一个文件,改文件扩展名必须是.repo才行!

要知道,yum会先下载软件仓库的清单到本机的/var/cache/yum里面去!如果我们修改了网址却没有修改软件仓库名称(中括号中的文字),可能就会造成本机的清单与yum服务器的清单不同步,就会出现无法更新的问题。

这是就需要清除本机上面的旧资料即可,清除的是/var/cache/yum/里面的文件。

清除资料


yum的软件组功能

通过yum来在线安装一个软件是非常简单,但是,如果要安装一个大型项目呢?如安装一个KDE?

yum group*功能


yum grouplist    #查看目前软件仓库与本机上面可用与安装过的软件组有哪些

还及得全新安装Centos时,不是可以选择所需要的软件吗?(mini最小化安装等),那就是软件群组。

yum groupinfo "Scientific Support"

yum groupinstall "Scientific Support"


全系统自动升级

我们可以手动选择是否需要升级,那能不能让系统自动升级,让我们的系统随时保持在最新的状态。

yum -y update    #自动升级

然后再写入crontab定时执行


管理的抉择:RPM还是Tarball

这是一个有趣的问题,如果我要升级或者是全新安装一个新软件,那么该选择RPM还是Tarball来安装呢?通常建议如下:

优先选择原厂的RPM功能;

选在软件官网发布的RPM或者是提供的软件仓库网址;

利用Tarball安装特殊软件;

用Tarball测试新版软件;

RPM与Tarball各有其优缺点,不过,如果有RPM的话,那么优先权还是在于RPM安装上面,毕竟管理上比较便利。但如果软件的架构差异性太大,或者是无法解决依赖性问题,那么就以Tarball来安装吧!


基础服务管理:以Apache为例

一般来说,WWW服务器需要有WWW服务器软件+网页程序语言+数据库系统+程序语言与数据库的连接软件等

另外,在默认的情况下,你无须修改服务的配置文件,通过系统默认值来处理你的服务即可!

1,安装:yum install 软件;

2,启动:systemctl start 软件;

3,开机自启:systemctl enable 软件;

4,防火墙:firewall-cmd --add-service=“服务”;firewall-cmd --add-service=“服务”;

5,测试:用软件检查你的服务是否正常。



SRPM的使用:rmpbuild(Optional)

新版的rpm已经将RPM与SRPM的指令分开了,SRPM使用的是rpmbuild这个命令,不是rpm。


利用默认值安装SRPM文件(--rebuid/--recompile)

直接编译并安装SRPM文件的主要选项:

rpmbuild的两个重要参数


这两个选项都不会修改SRPM的值,仅是通过再次编译来产生RPM可安装软件文件而已。

一般来说,如果你需要用到SRPM的文件,大部分原因就是你需要重新修改里面的某些设置,让软件加入某些特殊功能等等。


SRPM使用的路径与需要的软件

SRPM既然含有source code,那么其中必有配置文件,所以首先我们必须知道,这个SRPM在进行编译的时候会使用到哪些目录,这样才能够来修改!

假设使用root身份来进行SRPM的操作,会有以下目录:

此外,在编译过程中,可能会发生不明的错误,或者是设置的错误,这个时候就会在/tmp下产生一个相对应的错误文件,你可以根据该错误文件进行排错。编译成功之后,/root/rpmbuild/{SPECS,SOURCES,BUILD}等文件都会被杀掉,而只剩下放在/root/rpmbuild/RPMS下的文件了。


设置文件的主要内容(*.spec)

我们知道在/root/rpmbuild/SOURCES里面放置源码(Tarball)以及相关升级文件(patch file),而编译步骤(./configure, make,make install等)产生的文件就放置在/root/rpmbuild/SPECS文件中。

cd /root/rpmbuild/SPECS

vim xxx.spec

这个xxx.spec文件是将SRPM编译成RPM的配置文件,基本规则如下:

1,整个文件的开头都已Summary开始,这部分的设置都是最基础的说明内容;

2,然后每个不同的段落之间,都以%来作为开头,例如%prep与%install等;

系统整体信息方面:

上面几个资料通常都必须要写,但是如果你的软件没有依赖性的关系时,那么就可以不需要那个REquires。根据上面的设置,最终的文件名就是[ {name}-{Version}-{Release}-.{Arch}.rpm ] 的格式。

%description:软件的一个简短说明;

%prep:未进行设置或安装前,你要编译完成的RPM帮你事先做的事情,就是prepare。

#1,进行软件的补丁(patch)等相关工作;

#2,寻找软件所需的目录是否已经存在?确认用的!

#3,实现建立你的软件所需要的目录,或者事先需要进行的任务;

#4,如果待安装的Linux系统内已经有安装的时候可能会被覆盖掉的文件,那么就需要进行备份(backup)的工作了。

%build:这个段落就是在谈怎么make编译成为可执行的程序;

%install:编译完成后的安装;

%files:这个软件安装的文件都需要写到这里来;

%changelog:这个项目主要实在记录这个软件曾经的更新记录;


SRPM的编译命令(-ba/-bb)

要在/root/rpmbuild下文件编译或者是单纯的打包成为RPM或SRPM时,就需要rpmbuild命令与相关选项的帮助了。

rpmbuild -ba xxx.spec    #编译并同时产生RPM与SRPM文件;

rpmbuild -bb  xxx.spec    #仅编译成RPM文件;

这个时候系统就会这样做:

1,先进入BUILD这个目录,/root/rpmbuild/BUILD;

2,依照xxx.spec文件内的Name与Version定义出工作的目录名称,并进入该目录;

3,在新建的目录里面,针对SOURCES目录下的来源文件,也就是xxx.spec里面的Source设置的那个文件,以tar进行解压缩;

4,再来开始%build以及%install的设置与编译;

5,最后将完成打包的文件给他放置到该放置的地方去。


一个打包自己软件的范例

我们来自己编辑一下自己制作的RPM怎么样?哈哈哈!

制作源码文件Tarball生成:

建立xxx.spec的设置文件:

这个文件的配置是所有rpm制作里面最重要的课题!

编译成为RPM与SRPM:

那个spec文件配置妥当后,后续的动作就简单的要命了!

安装/测试/实际查询:

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,560评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,104评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,297评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,869评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,275评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,563评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,833评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,543评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,245评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,512评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,011评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,359评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,006评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,062评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,825评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,590评论 2 273
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,501评论 2 268

推荐阅读更多精彩内容