linux下安装mariadb(mysql)并创建账户

安装mariadb(mysql)并创建账户

(red hat内置的安装已经是mariadb,而非mysql,因为二者差不多,所以不建议重新下载mysql,建议直接用mariadb)

安装:

[root@localhost ~]# dnf -y install mariadb*

启动:

[root@localhost ~]# systemctl start mariadb

[root@localhost ~]# systemctl status mariadb

[root@localhost ~]# firewall-cmd --permanent --add-service=mysql

[root@localhost ~]# firewall-cmd --reload

[root@localhost ~]# firewall-cmd --permanent --add-service=mariadb

Error: INVALID_SERVICE: mariadb

[root@localhost ~]# mysql_secure_installation

进入root下的mariadb(即mysql)

[root@localhost ~]# mysql -u root -p

Enter password: (这里要输入密码)

Welcome to the MariaDB monitor.  Commands end with ; or g.

Your MariaDB connection id is 13

Server version: 10.1.26-MariaDB MariaDB Server



Copyright (c) 2000, 2017, Oracle, MariaDB Corporation Ab and others.



Type 'help;' or 'h' for help. Type 'c' to clear the current input

输入密码后进入

MariaDB [(none)]>





#------

建账户:

MariaDB [(none)]> create database menmydb;

Query OK, 1 row affected (0.02 sec)

创建密码:

MariaDB [(none)]> create user menxiaolei@localhost identified by 'men12xiao34lei56';

Query OK, 0 rows affected (0.02 sec)

给权限:

MariaDB [(none)]> grant all on menmydb.* to menxiaolei@localhost identified by 'men12xiao34lei56';

Query OK, 0 rows affected (0.02 sec)

退出

MariaDB [(none)]>



Ctrl+D

#——————————————————–

普通用户使用menmydb

[xjj@localhost ~]$ mysql -u menxiaolei -p

Enter password: (这里输入密码)

Welcome to the MariaDB monitor.  Commands end with ; or g.

Your MariaDB connection id is 17

Server version: 10.1.26-MariaDB MariaDB Server



Copyright (c) 2000, 2017, Oracle, MariaDB Corporation Ab and others.



Type 'help;' or 'h' for help. Type 'c' to clear the current input statement.
MariaDB [(none)]> show databases;

+--------------------+

| Database           |

+--------------------+

| information_schema |

| menmydb            |

+--------------------+

2 rows in set (0.00 sec)
MariaDB [(none)]> show tables;



MariaDB [(none)]> describe servers;



Ctrl+D

Linux两块磁盘挂载指向一个文件夹LVM磁盘管理(三)

注意:任何磁盘的操作有可能损坏里面数据,请提前备份数据,切记!切记!切记!

0x00:LVM常用命令对照。

针对LVM底层PV的一些基本操作

对于底层的PV而言,操作的命令如下表所示:

未分类

针对LVM中层VG的一些基本操作

对于中层的VG而言,操作的命令如下表所示

未分类

针对LVM上层LV的一些基本操作

对于上层的LV而言,操作命令如下表所示:

未分类

Linux两块磁盘挂载指向一个文件夹LVM磁盘管理(二)

注意:任何磁盘的操作有可能损坏里面数据,请提前备份数据,切记!切记!切记!

0x00:前言

VG卷组的总空间是受物理磁盘大小限制,本教程有3块物理磁盘分别是100M、200M、300M,那么VG卷组总空间就是600M;而VG下所有的LV累加的总空间又受限于VG。

使用过程中LV早晚会用完,那么上面的/LVM挂载点只能同时挂载一个,而有些程序不能支持有两个文件目录,比如WEB只有一个/,还有MySQL。

0x01:扩展VG卷组、缩小VG卷组

1)扩展VG卷组

上一章讲我看到添加了3块物理磁盘,第一块(/dev/sdb1)已经加入VG组,这次来把第二块(/dev/sdc1)加入到之前的那个vgdata的VG组里。

首先还是格式化磁盘,并创建磁盘分区/dev/sdc1。这里图略,和之前一样。

# fdisk /dev/sdc  //显示创建磁盘并和格式化,略去一些命令

略。

# pvcreate /dev/sdc1   //普通磁盘转换成PV
# pvs  //查看VG组信息
# vgextend vgdata /dev/sdc1   //加入VG组,vgdata要加入VG组名,/dev/sdc1新PV

图里可以看到磁盘第一次pvs里只有一个PV,添加后,第二次pvs就又有多出一块PV。

未分类

# vgdisplay  //查看VG卷组详细信息,VG的总空间已经由之前100M变成300M

未分类

2).缩小卷组

实际使用中,因为磁盘损坏,或空间分配问题,我们需要从VG卷组删除一个PV物理卷。用过的PV物理卷肯定会被写入数据,那么在移走PV前,我们要先迁移数据。

先用pvdisplay命令看看上面PE块被写了多少数据,假如/dev/sdb1是要移走的物理硬盘。

注意,目的地空闲空间要大于/dev/sdb1。

我们准备了/dev/sdd1来存放迁移过来的数据。

未分类

从上图可以看出sdb1总空间是100M,然后空闲是0M,也就是使用了100M。

# pvmove -i 1 /dev/sdb1 /dev/sdd1  //将sdb1数据移动到sdd1里,
                                              -i 1是每1秒钟报告一次数据迁移的进度。
# vgreduce vgdata /dev/sdb1  //将/dev/sdb1从vgdata卷组中移除
#  pvremove /dev/sdb1  //将/dev/sdb1移除出PV

未分类

结果:数据没有任何丢失。

未分类

0x02:扩展LV、缩小LV逻辑卷

1)VG卷组又有新的空间,而刚才创建的lvData(/dev/sdb1)已经使用完了,我们来扩展LV。

# lvextend –L +50M /dev/vgdata/lvData
或者
# lvextend –l 150M /dev/vgdata/lvData

-L和-l区别,-L后是写你要增加多少,而-l是写你要增加到的总数。

执行命令后我们发现LV size变成150M了。

未分类

LV扩容完系统还没有识别,需要用resize2fs来更新,系统才能识别到。

# resize2fs /dev/vgdata/lvData

未分类

2)缩小LV(逻辑卷)空间。

使用过程中LV空间总会分配不合理或大或小,如果分配大了,不用又造成空间浪费,现在将LV(逻辑卷)缩小以分配给其他LV(逻辑卷)用。

我们之前创建了一个LV(逻辑卷),挂载到了/LVM下。

未分类

调整钱我们先要卸载挂载点,因为挂载后是使用状态,不允许操作。如图,卸载成功。

# umount /LVM

未分类

检查文件系统是否有坏块,这部检查必须要做。

# e2fsck -f /dev/mapper/vgdata-lvData

未分类

从上面df -h 知道,总空间287M,使用128M,剩余146M空间。我们缩小总空间到250M,做演示。

注意:缩小LV前,先要缩小PV,resize2fs在前,lvreduce在后,顺序不能错。

# resize2fs /dev/mapper/vgdata-lvData 250M  //缩小PV

未分类

# lvreduce -L 250M /dev/mapper/vgdata-lvData
或
# lvreduce -L -50M /dev/mapper/vgdata-lvData  //-50M,在原基础上减去50M空间。

未分类

好了,缩减成功,挂载看看。

# mount -a

# mount /dev/vgdata/lvData  /lvm

因为PE默认4M,我们给的250M的PE不一定对其,所以系统会从新计算PE倍数来对其,显示的数就会小于我们写的数。

未分类

注意:/dev/mapper/vgdata-lvData和/dev/vgdata/lvData是一样的,指向同一路径。

查看PV有多少空闲空间。显示多出48M的空闲空间。

# pvs

未分类

0x03:LV测试篇

写此文章的时候,我就在想如果物理磁盘空间不够,但是LV分配很大,会发生什么现象。

看下图,我在虚拟机里创建了一个5G的虚拟磁盘文件放到D盘。我的电脑D盘,用一些其他东西故意填满,只留下了很少的空闲空间。

下面还有个3G的磁盘,我放到了C盘,C盘空闲空间充足。

未分类

接着将上面创建两个盘在系统里转换成PV物理卷->加入VG卷组->加入LV卷。

未分类

LVM的存放数据的规律是由那个PV先被添加就先存放到哪个PV上,直到PV存满才到下一个PV上存。

sde1就是我们放到上图显示D盘的那个文件,一会写文件先往sde1里写,然后在往sdf1里写。

我们找来一个ISO镜像(大于4G的文件),来往里面拷贝数据,看看发生什么?

未分类

上传数据的过程中,D盘空间用完了,LVM而并没有尝试切换到sdf1的3G这空间去复制,而是直接报了系统错误,而且系统因为没有空间,直接退出了,重新启动都没成功,只好将D盘里删除一些文件,才将系统重新启动。

未分类

总结,PV的设置最大值不能超过物理磁盘的空间,否则会出现丢失数据的问题。

0x04:LVM快照

(转:http://www.linuxidc.com/Linux/2017-05/143774.htm)。

LVM快照是一种以空间换时间时间的方式制作的lvm卷副本。它只在lvm中工作,并只在源逻辑卷发生改变时占用快照卷的空间。如果源卷的变化达到1GB这么大,快照卷同样也会产生这样大的改变。因而,对于空间有效利用的最佳途径,就是总是进行小的修改。如果快照将存储空间消耗殆尽,我们可以使用lvextend来扩容。而如果我们需要缩减快照所占用卷的大小,可以使用lvreduce。实验如下:目标逻辑卷信息如下:

$ pvs
PV         VG   Fmt  Attr PSize PFree
/dev/sdb   vg0  lvm2 a--  7.00g    0 
/dev/sdd1  vg0  lvm2 a--  7.00g 1.99g
$ vgs
VG   #PV #LV #SN Attr   VSize  VFree
vg0    2   1   0 wz--n- 13.99g 1.99g
$ lvs
LV   VG   Attr       LSize  Pool Origin Data%  Meta%  Move Log Cpy%Sync Convert
lv0  vg0  -wi-ao---- 12.00g

现在对逻辑卷lv0创建快照,命名为snaplv0

$ lvcreate -s -n snaplv0 -p r -L 1G /dev/vg0/lv0
Logical volume "snaplv0" created.
$ vgs
VG   #PV #LV #SN Attr   VSize  VFree   
vg0    2   2   1 wz--n- 13.99g 1016.00m
$ lvs
LV   VG   Attr   LSize  Pool Origin Data%  Meta%  Move Log Cpy%Sync Convert
lv0     vg0  owi-aos--- 12.00g 
snaplv0 vg0  sri-a-s---  1.00g      lv0    0.00

这里/dev/vg0/lv0的挂载点为/mnt。往/mnt里面写入300MB的随机文件,再观察快照情况,可以看 到,快照对应的Data一项有所增长:

$ dd if=/dev/urandom of=/mnt/2.txt bs=1M count=300
300+0 records in
300+0 records out
314572800 bytes (315 MB) copied, 27.5877 s, 11.4 MB/s
$ ls
1.txt  2.txt  data
$ lvs
LV   VG   Attr   LSize  Pool Origin Data%  Meta%  Move Log Cpy%Sync Convert
lv0  vg0  owi-aos--- 12.00g
snaplv0 vg0  sri-a-s---  1.00g      lv0    29.42

用snaplv0对逻辑卷进行恢复,注意恢复之前需要先将对应的逻辑卷卸载。恢复之后可以看到,原有的snaplv0消失,因此可以得出结论,LVM的快照是一次性的:

$ umount /mnt
$ lvconvert --merge /dev/vg0/snaplv0
Merging of volume snaplv0 started.
lv0: Merged: 71.0%
lv0: Merged: 91.9%
lv0: Merged: 100.0%
$ ls /dev/vg0
lv0
$ mount /dev/vg0/lv0 /mnt
$ ls /mnt
1.txt  data

如果想要删除LVM快照,用lvremove命令,后面跟上快照设备文件的绝对路径即可,例如:

$ lvremove /dev/vg0/snaplv0

0x05:删除LVM

删除LVM,先取消开机自动挂载,在取消挂载、取消LV、取消VG、取消PV,还原磁盘83类型。

# umount /lvm                            //取消挂载
# lvremove /dev/vgdata/lvData                //删除LV
# vgremove vgdata                            //删除vgdata组
# pvremove /dev/sdb1 /dev/sdc1 /dev/sdd1   //磁盘还原成普通磁盘
#  fdisk /dev/sdb1  //执行t ID输入83,让磁盘恢复普通磁盘。

Linux两块磁盘挂载指向一个文件夹LVM磁盘管理(一)

注意:任何磁盘的操作有可能损坏里面数据,请提前备份数据,切记!切记!切记!

0x00:前言

在Linux使用过程中,发现一个文件很大,比如5G,但是有两块物理磁盘一个剩下4G,一个剩3G,磁盘空间不够,这样肯定不能放进去。如果把5G文件分割了是可以放进去,但是如果有很多文件呢!这时候就可以用LVM来帮我们来管理文件是放到哪个磁盘里。

注意:LVM用于单块硬盘小于2TB的分区,如果超过2TB用part分区,不建议用LVM会识别不了。

0x01:文本对照

物理磁盘:即你购买来能拿在手里的那一块磁盘。

PV:物理卷(physical volume)。物理磁盘创建成普通磁盘83后,将类型修改成8e时,其成为LVM磁盘系统,也就是我们说的PV。

VG:逻辑卷组(Volume Group)。是将一个个的PV放到一个组里统一管理。

LV:逻辑卷(logical volume)。也就是从VG中划分的逻辑分区,在这上我们可以当成普通磁盘去使用,新建一个文件或文件夹。

0x02:版本说明

1)VMware Workstation 12 Pro 12.5.7 build-5813279
2)CentOS release 6.9 (Final)

0x03:实验环境搭建

1)安装VM虚拟机以及CentOS系统安装网上很多,略。

2)在VM里创建模拟物理磁盘,虚拟机里会自动识别。

未分类

未分类

未分类

因为做实验节省时间,所以我们将3个磁盘只分了100M、200M、300M,

从容量上我们也可以直观看到在操作的磁盘。

未分类

注意文件名不要重复

未分类

另外2个创建是一样的,重复上面步骤即可。

未分类

在系统中用命令查看,多出几块未分配的磁盘。

# fdisk -l

未分类

3)首先,把磁盘格式化成普通磁盘。

#fdisk /dev/sda

未分类

未分类

0x04:安装LVM,及创建。

将一块普通磁盘类型修改成8e时,其已经成为LVM磁盘系统里,也就是我们说的PV。

磁盘创建好了,但是LVM并不是系统自带的,尤其是2.6.9以下,需要我们自己安装。

查看系统是否安装。

rpm -qa | gre lvm

并查看内核版本。

uname -a

系统显示没有安装,我们用命令安装。

yum -y install lvm2

未分类

1)创建PV。

LVM提示已经安装完成,用pvscan命令提示没有发现PV(physical volumes)

未分类

创建PV,并重新扫描,发现了一个新的PV。

# pvcreate /dev/sdb1
# pvscan

未分类

显示PV信息,因为只创建一个PV,所以只有一个。

# pvdisplay

未分类

好了,现在将一块普通磁盘改变成LVM里最基本物理磁盘。下面我们来创建VG(磁盘管理组)。

2)创建VG(卷组),来管理PV。

# vgscan  //因为之前没有创建过VG,所以扫描没有显示。
# vgcreate vgdata /dev/sdb1   //创建vgdata并将/dev/sdb1加入
#  vgcreate vgdata /dev/sdb1  -s 8M //-s是指定PE大小,默认是4M
# vgdisplay  //显示VG信息

未分类

再次扫描,发现上面创建的“vgdata”卷组VG了。

未分类

3)有了卷组我们就可以创建LV,LV是我们真正用来写数据的,比如新建一个文本等。

# lvscan //扫描LV,之前没有建立过LV,什么也没显示
# lvcreate -L 100M -n lvData vgdata //创建LV,-L 指定LV大小为100M,-n LV名字方便区分,
vgdata 加入到vgdata组,上面创建的。
# lvdisplay

未分类

4)格式化LV及挂载

# mkfs.ext4 /dev/vgdata/lvData  //格式化lvData为ext4格式。
#  mkdir /LVM  //创建挂载点
#  mount /dev/vgdata/lvData  /LVM  //挂载到LVM下
#  df -h  显示挂载成功100M空间系统占用1.6M还要卷组占用一些,实际占用2%。

未分类

好了,到此一个完整的LVM就创建完了。

0x05:开机自动挂载

挂载点的磁盘,在重启后就会丢失,需要将配置写入/etc/fstab,让系统自动挂载。

# echo "/dev/vgdata/lvData  /LVM    ext4    defaults 0 0" >> /etc/fstab

未分类

Linux iptables防火墙原理与常用配置

Linux系统中,防火墙(Firewall),网址转换(NAT),数据包(package)记录,流量统计,这些功能是由Netfilter子系统所提供的,而iptables是控制Netfilter的工具。iptables将许多复杂的规则组织成成容易控制的方式,以便管理员可以进行分组测试,或关闭、启动某组规则。iptable只读取数据包头,不会给信息流增加负担,也无需进行验证。

iptables结构

  
iptables由4表、5链和用户在链内写入的各种规则所组成。

1、表:容纳各种规则链;

表是按照功能分的类,具体功能如下:

(1)raw表:用来决定是否对数据包进行状态跟踪。(不常用)

(2)mangle表:为数据包设置标记,有ACK、SYN、FIN、RST、PSH、URG等标记。(不常用)

(3)nat表:修改数据包的IP地址、端口等信息。(网关型防火墙常用)

(4)filter表:确定是否放行数据包。(常用)

2、链:容纳各种防火墙规则;

链是按照时机分的类。

(1)input:处理入站请求包

(2)output:处理出站包(就是响应、应答包)

(3)forward:处理转发数据包,实现不同网段间的通信

(4)prerouting:在包做路由选择之前应用此链的规则

(5)postrouting:在数据包做路由选择之后应用此链的规则

表的处理优先级:raw > mangle > nat > filter

详细的数据包流程:

未分类

iptable应用场景

未分类

上图是应用场景的简单拓扑描述,下面的应用场景举例,都以上图为参考.

系统启动的时候所有的默认策略都是ACCEPT,在下面的场景举例中,我们都是在这种前提下设定iptable的。下面每个场景举例都是独立的,没有相关联性的。

网关服务器安全策略

目标 : 网关服务器系统自生安全策略,只对内网用户开放22端口(sshd服务)

#清空 filter table
[root@localhost]# iptables -F -t filter
[root@localhost]# iptables -X -t filter
[root@localhost]# iptables -Z -t filter

#清空 nat table
[root@localhost]# iptables -F -t nat
[root@localhost]# iptables -X -t nat
[root@localhost]# iptables -Z -t nat

#设置默认策略(INPUT链默认为DROP)
[root@localhost]# iptables -t filter -P INPUT DROP
[root@localhost]# iptables -t filter -P OUTPUT ACCEPT
[root@localhost]# iptables -t filter -P FORWARD ACCEPT

#回环接口(lo),默认accept
[root@localhost]# iptables -A INPUT -p ALL -i lo -j ACCEPT

#只对内网用户开放sshd服务
[root@localhost]# iptables -A INPUT -p tcp -s 192.168.138.0/24 --dport 22 -j ACCEPT

说明: 防火墙的策略顺序一般都是 从 非信任 ==> 信任,默认关闭所有访问权限,然后按照需要逐条开放访问权限.

共享上网(nat)

目标:使局域网的用户都可以访问外网的服务器

[root@localhost]# echo 1 > /proc/sys/net/ipv4/ip_forward
[root@localhost]# iptables -t nat -A POSTROUTING -o ppp0 -j MASQUERADE

说明: SNAT 和 MASQUERADE 区别

SNAT : 不管是几个地址,必须明确的指定要SNAT的ip,适合网关服务器有固定地址或者是固定地址范围. MASQUERADE : 是针对ADSL动态拨号这种场景而设计,从服务器的网络接口上,自动获取当前ip地址来做NAT,这样就实现了动态SNAT地址转换

内网的服务器对外服务(端口映射)

目标:使外网用户可以访问到局域网192.168.138.21这台HTTP服务

[root@localhost]# echo 1 > /proc/sys/net/ipv4/ip_forward
[root@localhost]# iptables -t nat -A PREROUTING -p tcp -m tcp --dport 80 -j DNAT --to-destination 192.168.138.21
[root@localhost]# iptables -t nat -A POSTROUTING -o ppp0 -j MASQUERADE

在网关服务器进行透明代理

目标: 使局域网用户,访问外网web服务时,自动使用squid作web透明代理服务器。

[root@localhost]# echo 1 > /proc/sys/net/ipv4/ip_forward
[root@localhost]# iptables -t nat -A PREROUTING -s 192.168.138.0/24 -p tcp --dport 80 -i eth0 -j DNAT --to 192.168.138.1
[root@localhost]# iptables -t nat -A PREROUTING -s 192.168.138.0/24 -p tcp --dport 80 -i eth0 -j REDIRECT --to 3128 
[root@localhost]# iptables -t nat -A POSTROUTING -o ppp0 -j MASQUERADE 

注意:iptables写入的规则重启会自动失效,需要使用/etc/rc.d/init.d/iptables save 保存到文件,重启才会自动读取文件上的配置,且使用iptables save保存之后,重启iptables服务:service iptables restart

iptables命令详解

iptables(选项)(参数)

-t<表>:指定要操纵的表; 
-A:向规则链中添加条目; 
-D:从规则链中删除条目; 
-i:向规则链中插入条目; 
-R:替换规则链中的条目; 
-L:显示规则链中已有的条目; 
-F:清楚规则链中已有的条目; 
-Z:清空规则链中的数据包计算器和字节计数器; 
-N:创建新的用户自定义规则链;
-X:用于删除用户自定义的空链,使用方法跟-N相同,但是在删除之前必须要将里面的链给清空; 
-P:定义规则链中的默认目标; 
-h:显示帮助信息; 
-p:指定要匹配的数据包协议类型; 
-s:指定要匹配的数据包源ip地址; 
-j<目标>:指定要跳转的目标; 
-i<网络接口>:指定数据包进入本机的网络接口; 
-o<网络接口>:指定数据包要离开本机所使用的网络接口。

iptables命令选项输入顺序:

iptables -t 表名 <-A/I/D/R> 规则链名 [规则号] <-i/o 网卡名> -p 协议名 <-s 源IP/源子网> 
             --sport 源端口 <-d 目标IP/目标子网> --dport 目标端口 -j 动作

表名包括:

  • raw:高级功能,如:网址过滤。

  • mangle:数据包修改(QOS),用于实现服务质量。

  • nat:地址转换,用于网关路由器。

  • filter:包过滤,用于防火墙规则。

规则链名包括:

  • INPUT链:处理输入数据包。

  • OUTPUT链:处理输出数据包。

  • PORWARD链:处理转发数据包。

  • PREROUTING链:用于目标地址转换(DNAT)。

  • POSTOUTING链:用于源地址转换(SNAT)。

动作包括:

  • ACCEPT:接收数据包。

  • DROP:丢弃数据包。

  • REDIRECT:重定向、映射、透明代理。

  • SNAT:源地址转换。

  • DNAT:目标地址转换。

  • MASQUERADE:IP伪装(NAT),用于ADSL。

  • LOG:日志记录。

LINUX搭建LAMP(APACHE+PHP+MYSQL环境)CENTOS7.2版

我们更多的网站服务器是选择了Linux系统,这里建议你选择centos,这也是阿里云ecs推荐的系统,在服务器上比较推荐centos,特别对于新手,首选CentOS,并不是centos比Debian和ubuntu好,而是centos是初学者安装vps的首选,它既稳定,占用资源又少此版本生命周期较长,而且网上有关centos的教程很多,方便学习,我们这里选择了Centos7.2,采用yum在线安装。

一、 检查系统环境

1、确认centos版本

[root@localhost ~]# cat /etc/redhat-release
CentOS Linux release 7.2.1511 (Core)

2、检查是否安装过apache

rpm -qa | grep httpd

或者:

apachectl -v

或者:

httpd -v

3、检查是否安装过Mysql

service mysqld start

如果未被识别则没有安装
如果系统安装过,或者安装失败,清理一下系统

4、清理Mysql痕迹

yum remove mysql
rm -f /etc/my.cnf

5、卸载Apache包

rpm -qa|grep httpd

注意:如果是新的系统或者你从来没有尝试安装过,则以上步骤省略。

二、安装APACHE、PHP、MYSQL

1、安装apache

[root@localhost ~]# yum -y install httpd

直到返回

......
Installed:
  httpd.x86_64 0:2.4.6-40.el7.centos.4                                          

Dependency Installed:
  apr.x86_64 0:1.4.8-3.el7                      apr-util.x86_64 0:1.5.2-6.el7   
  httpd-tools.x86_64 0:2.4.6-40.el7.centos.4    mailcap.noarch 0:2.1.41-2.el7   

Complete!

表示安装成功!

2、安装Php

[root@localhost ~]# yum -y install php

直到返回:

......
Installed:
  php.x86_64 0:5.4.16-36.3.el7_2                                                

Dependency Installed:
  libzip.x86_64 0:0.10.1-8.el7             php-cli.x86_64 0:5.4.16-36.3.el7_2   
  php-common.x86_64 0:5.4.16-36.3.el7_2   

Complete!

3、安装php-fpm

[root@localhost ~]# yum -y install php-fpm

直到返回:

Installed:
  php-fpm.x86_64 0:5.4.16-36.3.el7_2                                            

Complete!

4、安装Mysql

[root@localhost ~]# yum -y install mysql

直到返回:

Installed:
  mariadb.x86_64 1:5.5.50-1.el7_2                                               

Dependency Updated:
  mariadb-libs.x86_64 1:5.5.50-1.el7_2                                          

Complete!

7.2版本的Centos已经把mysql更名为mariadb,表示安装成功!

5、安装 mysql-server

[root@localhost ~]# yum -y install mysql-server
Loaded plugins: fastestmirror, langpacks
Loading mirror speeds from cached hostfile
 * base: mirror.lzu.edu.cn
 * extras: mirrors.nwsuaf.edu.cn
 * updates: mirrors.tuna.tsinghua.edu.cn
No package mysql-server available.
Error: Nothing to do

返回错误!!!

分析解决方案

CentOS 7+ 版本将MySQL数据库软件从默认的程序列表中移除,用mariadb代替了,entos7配置教程上,大多都是安装mariadb,因为centos7默认将mariadb视作mysql。

因为mysql被oracle收购后,原作者担心mysql闭源,所以又写了一个mariadb,这个数据库可以理解为mysql的分支。如果需要安装mariadb,只需通过yum就可。

解决方案:

二是从官网下载mysql-server

wget http://dev.mysql.com/get/mysql-community-release-el7-5.noarch.rpm

rpm -ivh mysql-community-release-el7-5.noarch.rpm

yum install mysql-community-server

然后需要确定,输入y回车即可

Install  3 Packages (+8 Dependent packages)

Total download size: 82 M
Is this ok [y/d/N]:

一直选择输入 y ,有两次选择,直到返回:

Replaced:
  mariadb.x86_64 1:5.5.50-1.el7_2      mariadb-libs.x86_64 1:5.5.50-1.el7_2     

Complete!

安装成功!!!

6、安装 php-mysql

[root@localhost ~]# yum -y install php-mysql

直到返回:

Installed:
  php-mysql.x86_64 0:5.4.16-36.3.el7_2                                          

Dependency Installed:
  php-pdo.x86_64 0:5.4.16-36.3.el7_2                                            

Complete!

安装成功!!!

三、安装基本常用扩展包

1、安装Apache扩展包

yum -y install httpd-manual mod_ssl mod_perl mod_auth_mysql

返回

......
Installed:
  httpd-manual.noarch 0:2.4.6-40.el7.centos.4                                   
  mod_ssl.x86_64 1:2.4.6-40.el7.centos.4                                        

Complete!

安装成功!!!

2、安装PHP扩展包

yum -y install php-gd php-xml php-mbstring php-ldap php-pear php-xmlrpc php-devel

返回:

......
Dependency Updated:
  pcre.x86_64 0:8.32-15.el7_2.1                                                 

Complete!

安装成功!!!

3、安装Mysql扩展包

yum -y install mysql-connector-odbc mysql-devel libdbi-dbd-mysql

返回:

......
Dependency Installed:
  libdbi.x86_64 0:0.8.4-6.el7         libdbi-drivers.x86_64 0:0.8.3-16.el7     
  unixODBC.x86_64 0:2.3.1-11.el7     

Complete!

安装成功!!!

四、配置APACHE、MYSQL开机启动

重启Apache、mysql服务(注意这里和centos6有区别,Cenots7+不能使用6的方式)

systemctl start httpd.service #启动apache
systemctl stop httpd.service #停止apache
systemctl restart httpd.service #重启apache
systemctl enable httpd.service #设置apache开机启动

启对应服务

service mysqld restart

service php-fpm start

service httpd restart

五、配置MYSQL

初次安装mysql是没有密码的,我们要设置密码,mysql的默认账户为root

设置 MySQL 数据 root 账户的密码:

[root@localhost ~]# mysql_secure_installation

当出现如下提示时候直接按回车:

Enter current password for root

出现如下再次回车:

Set root password? [Y/n]

出现如下提示输入你需要设置的密码,这里输入了root,输入密码是不显示的,回车后再输入一次确认:

New password:

接下来还会有四个确认,分别是:

Remove anonymous users? [Y/n]
Disallow root login remotely? [Y/n]
Remove test database and access to it? [Y/n]
Reload privilege tables now? [Y/n]

直接回车即可。

六、测试环境

1、我们在浏览器地址栏输入http://localhost/如下图,说明我们的apache测试成功

未分类

2、测试Php

进入apache的web根目录:/var/www/html 中写一个最简单的php测试页面

cd /var/www/html

touch phpinfo-test.php

vi phpinfo-test.php

进入到了控制模式之后按键盘字母 i 进入到编辑模式,将如下代码输入到文件中

<?php

echo "<title>Phpinfo Test.php</title>";

phpinfo()

?>

按 esc 退出编辑模式,回到控制模式,输入 :wq 然后回车,在浏览器中输入服地址http://localhost/phpinfo-test.php

出现下图则成功。

未分类

七、小结

1、我们采用了yum在线安装,版本都是默认的Php是5.4,apache的版本是Server version: Apache/2.4.6 (CentOS)

2、要想安装更高版本的php 阅读:centos7.2yum安装php70w.x86_64

3、以上教程亲测完成成功,极力推荐,如果你在调试过程中出现问题,留言讨论,如有错误,敬请指教。

Linux下安装Apache httpd

httpd是Apache超文本传输协议(HTTP)服务器的主程序。它被设计为一个独立运行的后台进程,它会建立一个处理请求的子进程或线程的池对外提供服务。httpd支持基于 虚拟主机,以及基于HOST、IP、PORT实现虚拟主机,反向代理,负载均衡,路径别名,用户认证,basic,支持第三方模块等众多特性。本文主要描述了Linux下httpd的安装以及相关基本用法。

一、httpd的安装

演示环境及版本

# cat /etc/issue
CentOS release 6.5 (Final)
Kernel r on an m

# uname -r
2.6.32-431.el6.x86_64

查看httpd是否已安装

# rpm -qa httpd

使用yum列出相关httpd安装文件,此处为本地yum源

# yum list |grep httpd     
httpd.x86_64                 2.2.15-29.el6.centos        local_server 
httpd-devel.i686             2.2.15-29.el6.centos        local_server 
httpd-devel.x86_64           2.2.15-29.el6.centos        local_server 
httpd-manual.noarch          2.2.15-29.el6.centos        local_server 
httpd-tools.x86_64           2.2.15-29.el6.centos        local_server 

安装及验证httpd

# yum -y install httpd
# rpm -qa |grep httpd
httpd-tools-2.2.15-29.el6.centos.x86_64
httpd-2.2.15-29.el6.centos.x86_64

使用rpm方式寻找配置文件

# rpm -qc httpd  

常用的配置文件:

/etc/httpd/conf.d/*.conf        ###辅助配置文件
/etc/httpd/conf/httpd.conf      ###主配置文件
/etc/sysconfig/httpd            ###httpd工作模式配置文件

使用rpm方式查看安装位置及生成的二进制文件

# rpm -ql httpd  

主程序:

/usr/sbin/httpd  MPM模式默认
/usr/sbin/httpd.event
/usr/sbin/httpd.worker

使用rpm方式查看包的帮助文件

# rpm -qd httpd   

启动脚本:/etc/rc.d/init.d/httpd

日志文件目录:

/var/log/httpd
    access_log:访问日志
    error_log: 错误日志

站点文档目录:(站点根目录)

/var/www/html

httpd的工作目录:/var/www

二、httpd的工作模式

1、MPM: Multipath Processing Module(多路处理模块)

prefork: 多进程模型,每个进程响应一个请求;稳定性好,但并发能力有限;预先生成多个空闲进程;

由于prefork使用select()系统调用,所以最大并发不能超过1024;

worker:多进程模型,每个进程可生成多个线程,每个线程响应一个请求;预先生成多个空闲线程;

event:一个进程直接响应n个请求;可同时启动多个进程;

httpd-2.2: 测试使用; ### Author : Leshami
httpd-2.4: 可生产使用; ### Blog : http://blog.csdn.net/leshami

2、几种工作方式的切换

prefork模式下

    # service httpd start
    Starting httpd:                                            [  OK  ]
    # ps -ef|grep httpd |grep -v grep ###一个主进程,生成了8个空闲进程
    root       6413      1  0 09:40 ?        00:00:00 /usr/sbin/httpd
    apache     6416   6413  0 09:40 ?        00:00:00 /usr/sbin/httpd
    apache     6417   6413  0 09:40 ?        00:00:00 /usr/sbin/httpd
    apache     6418   6413  0 09:40 ?        00:00:00 /usr/sbin/httpd
    apache     6419   6413  0 09:40 ?        00:00:00 /usr/sbin/httpd
    apache     6420   6413  0 09:40 ?        00:00:00 /usr/sbin/httpd
    apache     6421   6413  0 09:40 ?        00:00:00 /usr/sbin/httpd
    apache     6422   6413  0 09:40 ?        00:00:00 /usr/sbin/httpd
    apache     6423   6413  0 09:40 ?        00:00:00 /usr/sbin/httpd   

    # ss -tulpn |grep httpd
    tcp    LISTEN     0   128  :::80   :::*      users:(("httpd",6413,4),("httpd",6416,4),("httpd",6417,4),("httpd",6418,4),
    ("httpd",6419,4),("httpd",6420,4),("httpd",6421,4),("httpd",6422,4),("httpd",6423,4)

    # netstat -nltp|grep 80
    tcp        0      0 :::80                       :::*          LISTEN      6413/httpd   

worker工作方式

    # cat /etc/sysconfig/httpd|grep -v ^#
    HTTPD=/usr/sbin/httpd.worker

    # service httpd restart
    Stopping httpd:                                            [  OK  ]
    Starting httpd:                                            [  OK  ]
    [root@orasrv1 ~]# ps -ef|grep httpd|grep -v grep
    root       2261      1  0 17:47 ?        00:00:00 /usr/sbin/httpd.worker
    apache     2264   2261  0 17:47 ?        00:00:00 /usr/sbin/httpd.worker
    apache     2265   2261  0 17:47 ?        00:00:00 /usr/sbin/httpd.worker
    apache     2266   2261  0 17:47 ?        00:00:00 /usr/sbin/httpd.worker

event工作方式

注,尽管2.2版本可以设置工作方式为httpd.event,生产环境不建议使用

    # cat /etc/sysconfig/httpd|grep -v ^#
    HTTPD=/usr/sbin/httpd.event
    [root@orasrv1 ~]# service httpd restart
    Stopping httpd:                                            [  OK  ]
    Starting httpd:                                            [  OK  ]
    [root@orasrv1 ~]# ps -ef|grep httpd|grep -v grep
    root       2402      1  0 17:49 ?        00:00:00 /usr/sbin/httpd.event
    apache     2405   2402  0 17:49 ?        00:00:00 /usr/sbin/httpd.event
    apache     2406   2402  0 17:49 ?        00:00:00 /usr/sbin/httpd.event
    apache     2407   2402  0 17:49 ?        00:00:00 /usr/sbin/httpd.event

三、httpd模块化特性

高度模块化

core + modules, 
DSO: Dynamic Shared Object

模块目录:

/etc/httpd/modules: 符号链接文件
/usr/lib64/httpd/modules

模块的查看

    httpd -M          ###查看当前httpd进程的所有模块
    httpd.event -M    ###查看event工作模式下的所有模块 更正@20160712
    httpd.worker -M   ###worker工作模式下的所有模块  更正@20160712
    httpd.worker -l   ###worker工作模式下的核心模块  更正@20160712

模块的查看示例

    # httpd -M
    Loaded Modules:
     core_module (static)
     mpm_prefork_module (static)
     http_module (static)
     so_module (static)
     auth_basic_module (shared)
      ..............

    # httpd.event -l
    Compiled in modules:
      core.c
      event.c
      http_core.c
      mod_so.c

模块的动态装载与卸载

    # cp /etc/httpd/conf/httpd.conf /etc/httpd/conf/httpd.conf.bak
    # cat /etc/httpd/conf/httpd.conf |grep authn_alias_module
    LoadModule authn_alias_module modules/mod_authn_alias.so
    # vi /etc/httpd/conf/httpd.conf  ###注释mod_authn_alias.so模块
    # cat /etc/httpd/conf/httpd.conf |grep authn_alias_module
      #LoadModule authn_alias_module modules/mod_authn_alias.so
    # service httpd restart
    # httpd -M   ###使用该方式前后进行对比即可知道模块是否装载或卸载    

四、验证httpd服务

# echo "<h1>orasrv1.xlk.com</h1>" >/var/www/html/index.html
# curl http://192.168.21.10
<h1>orasrv1.xlk.com</h1>

两种方法解决Linux wget报错-bash: wget command not found

今天使用DigitalOcean的vps服务器,wget 时提示 -bash:wget command not found.

估计是安装的Linux系统, CentOS+7.4+x64wget软件包没有默认被安装。

可以通过以下两种方法来安装:

1、rpm 安装

rpm 下载源地址:http://mirrors.163.com/centos/6.5/os/x86_64/Packages/

下载wget的RPM包:http://mirrors.163.com/centos/6.5/os/x86_64/Packages/wget-1.12-1.4.el6.x86_64.rpm

rpm ivh wget-1.12-1.4.el6.x86_64.rpm 安装即可。

如果客户端用的是SecureCRT,linux下没装rzsz 包时,rz无法上传文件怎么办?

网上看到一个办法,安装另一个SSH客户端:SSH Secure Shell。然后传到服务器上安装,这个比较费劲,所以推荐用第二种方法。

2、yum安装

yum -y install wget

第二种方法明显更简单一些。不过如果yum包也没有安装的话,那就只能用第一种方法了。

顺便分享2个中国大陆开源镜像站,有需要的时候应该能提供不少方便:

搜狐开源镜像站:http://mirrors.sohu.com/

网易开源镜像站:http://mirrors.163.com/

Linux screen报错-bash: screen: command not found 解决

如果linux系统中没有安装screen。

会出现:-bash: screen: command not found

可以自行安装:

如果你使用yum软件包管理工具:yum install screen
如果你使用APT软件包管理工具:apt-get install screen

你也可以到Screen的官方网站去下载软件包,地址是:
http://www.gnu.org/software/screen/

剖析Linux系统调用的执行路径

在什么是操作系统这篇文章中,介绍过操作系统像是一个代理一样,为我们去管理计算机的众多硬件,我们需要计算机的一些计算服务、数据管理的服务,都由操作系统提供接口来完成。这样做的好处是让一般的计算机使用者不用关心硬件的细节。

1. 什么是操作系统的接口

既然使用者是通过操作系统接口来使用计算机的,那到底是什么是操作系统提供的接口呢?

接口(interface)这个词来源于电气工程学科,指的是插座与插头的连接口,起到将电与电器连接起为的功能。后来延伸到软件工程里指软件包向外提供的功能模块的函数接口。所以接口是用来连接两个东西、信号转换和屏蔽细节。

那对于操作系统来说:操作系统通过接口的方式,建立了用户与计算机硬件的沟通方式。用户通过调用操作系统的接口来使用计算机的各种计算服务。为了用户友好性,操作系统一般会提供两个重要的接口来满足用户的一些一般性的使用需求:

  • 命令行:实际是一个叫bash/sh的端终程序提供的功能,该程序底层的实质还是调用一些操作系统提供的函数。

  • 窗口界面:窗口界面通过编写的窗口程序接收来自操作系统消息队列的一些鼠标、键盘动作,进而做出一些响应。

对于非一般性使用需求,操作系统提供了一系列的函数调用给软件开发者,由软件开发者来实现一些用户需要的功能。这些函数调用由于是操作系统内核提供的,为了有别于一般的函数调用,被称为系统调用。比如我们使用C语言进行软件开发时,经常用的printf函数,它的内部实际就是通过write这个系统调用,让操作系统内核为我们把字符打印在屏幕上的。

为了规范操作系统提供的系统调用,IEEE制定了一个标准接口族,被称为POSIX(Portable Operating System Interface of Unix)。一些我们熟悉的接口比如:fork、pthread_create、open等。

2. 用户模式与内核模式

计算机硬件资源都是操作系统内核进行管理的,那我们可以直接用内核中的一些功能模块来操作硬件资源吗?可以直接访问内核中维护的一些数据结构吗? 当然不行!有人会说,为什么不行呢?我买的电脑,内核代码在内存中,那内存不都是我自己买的吗?,我自己不能访问吗?
现在我们运行的操作系统都是一个多任务、多用户的操作系统。如果每个用户进程都可以随便访问操作系统内核的模块,改变状态,那整个操作系统的稳定性、安全性都大大降低了。

为了将内核程序与用户程序隔离开,在硬件层面上提供了一次机制,将程序执行的状态分为了不同的级别,从0到3,数字越小,访问级别越高。0代表内核态,在该特权级别下,所有内存上的数据都是可见的,可访问的。3代表用户态,在这个特权级下,程序只能访问一部分的内存区域,只能执行一些限定的指令。

操作系统在建立GTD表的时候,将GTD的每个表项中的2位(4种特权级别)设置为特权位(DPL),然后操作系统将整个内存分为不同的段,不同的段,在GDT对应的表项中的DPL位是不同的。比如内核内存段的所有特权位都为00。而用户程序访存时,在保护模式下都是通过段寄存器+IP寄存器来访问的,而段寄存器里则用两位表示当前进程的级别(CPL),是位于内核态还是用户态。

既然如此,那我们还有什么办法可以调用操作系统的内核代码呢?操作系统为了实现系统调用,提供了一个主动进入内核的惟一方式:中断指令int。int指令会将GDT表中的DPL改为3,让我们可以访问内核中的函数。所以所有的系统调用都必须通过调用int指令来实现,大致的过程如下:

  • 用户程序中包含一段包含int指令的代码
  • 操作系统写中断处理,获取相调程序的编号
  • 操作系统根据编号执行相应的代码

3. 剖析printf函数

下面我们以printf函数的调用为例,说明该函数是如何一步一步最终落在内核函数上去的。

未分类
图1:应用程序、库函数和内核系统调用之间的关系

printf函数是C语言的一个库函数,它并不是真正的系统调用,在Unix下,它是通过调用write函数来完成功能的。

write函数内部就是调用了int中断。一般的系统调用都是调用0x80号中断。而操作系统中一般不会的显式的写出write的实现代码,而是通过_syscall3宏展开的实现。_syscall3是专门用来处理有3个参数的系统调用的函数的实现。同理还有_syscall0、_syscall1和_syscall2等,目前最大支持的参数个数为3个,这三个参数是通过ebx, ecx,edx传递的。如果有系统调用的参数超过了3个,那么可以通过一个参数结构体来进行传递。

// linux/lib/write.c
#define __LIBRARY__
#include <unistd.h>
// 
_syscall3(int,write,int,fd,const char *,buf,off_t,count)
// linux/include/unistd.h
#define _syscall3(type,name,atype,a,btype,b,ctype,c) 
type name(atype a,btype b,ctype c) 
{ 
long __res; 
__asm__ volatile ("int $0x80" 
    : "=a" (__res) 
    : "0" (__NR_##name),"b" ((long)(a)),"c" ((long)(b)),"d" ((long)(c))); 
if (__res>=0) 
    return (type) __res; 
errno=-__res; 
return -1; 
}

所以宏展开后,write函数的实现实现为:

int write(int fd, const char *buf, off_t count)
{ 
    long __res; 
    __asm__ volatile ("int $0x80" 
        : "=a" (__res) 
        : "0" (__NR_write),"b" ((long)(a)),"c" ((long)(b)),"d" ((long)(c))); 
    if (__res>=0) 
        return (type) __res; 
    errno=-__res; 
    return -1; 
}

我们看到实际函数内部并没有做太多的事情,主要就是调用int 0x80,将把相关的参数传递给一些通用寄存器,调用的结果通过eax返回。其中一个很重要的调用参数是__NR_write这个也是一个宏,就是wirte的系统调用号,在linux/include/unistd.h中被定义为4,同样还有很多其他系统调用号。因为所有的系统调用都是通过int 0x80,那怎么知道具体需要什么功能呢,只能通过系统调用号来识别。

下面我们来看看int 0x80是如何执行的。这是一个系统中断,操作系统对于中断处理流程一般为:

  • 关中断:CPU关闭中段响应,即不再接受其它外部中断请求
  • 保存断点:将发生中断处的指令地址压入堆栈,以使中断处理完后能正确地返回。
  • 识别中断源:CPU识别中断的来源,确定中断类型号,从而找到相应的中断服务程序的入口地址。
  • 保护现场所:将发生中断处理有关寄存器(中断服务程序中要使用的寄存器)以及标志寄存器的内存压入堆栈。
  • 执行中断服务程序:转到中断服务程序入口开始执行,可在适当时刻重新开放中断,以便允许响应较高优先级的外部中断。
  • 恢复现场并返回:把“保护现场”时压入堆栈的信息弹回原寄存器,然后执行中断返回指令(IRET),从而返回主程序继续运行。

前3项通常由处理中断的硬件电路完成,后3项通常由软件(中断服务程序)完成。

未分类
图2:系统调用中断处理流程

那0x80号中断的处理程序是什么呢,我们可以看一下操作系统是如何设置这个中断向量表的。在操作系统初始化时shecd_init函数里,调用了

set_system_gate(0x80, &system_call);

我们深入看一下set_system_gate函数做了什么

#define _set_gate(gate_addr,type,dpl,addr) 
__asm__ ("movw %%dx,%%axnt" 
    "movw %0,%%dxnt" 
    "movl %%eax,%1nt" 
    "movl %%edx,%2" 
    : 
    : "i" ((short) (0x8000+(dpl<<13)+(type<<8))), 
    "o" (*((char *) (gate_addr))), 
    "o" (*(4+(char *) (gate_addr))), 
    "d" ((char *) (addr)),"a" (0x00080000))

#define set_system_gate(n,addr) 
    _set_gate(&idt[n],15,3,addr)

通过上面的代码,我们可以看出,set_system_gate把第0x80中断表的表项中中断处理程序入口地址设置为&system_call。并且把那一项IDT表中的DPL设置了为3, 方便用户程序可以去访问这个地址。

所以init 0x80最终会被system_call这个函数地址处的代码来实际处理。让我们看下system_call做了什么事情。

# linux/kernel/system_call.s
nr_system_calls=72 # 最大的系统调用个数
.globl _system_call

system_call:
    cmpl $nr_system_calls-1,%eax    # eax中放的系统调用号,在write的调用过程中为__NR_write = 4
    ja bad_sys_call
    push %ds        # 下面是一些寄存器保护,后面还要弹出
    push %es
    push %fs
    pushl %edx
    pushl %ecx              # push %ebx,%ecx,%edx as parameters
    pushl %ebx              # to the system call
    movl $0x10,%edx         # set up ds,es to kernel space
    mov %dx,%ds             # 把ds的段标号设置为0001 0000(最后2位是特权级),所以段号为4,内核态数据段
    mov %dx,%es
    movl $0x17,%edx     # 把fs的段标号设置为0001 0111(最后2位是特权级),所以段号为5,用户态数据段
    mov %dx,%fs
    call sys_call_table(,%eax,4)        # 实际的系统调用
    pushl %eax
    movl current,%eax
    cmpl $0,state(%eax)     # state 检测是否为就绪状态
    jne reschedule                        # 进入调度程序
    cmpl $0,counter(%eax)       # counter 查看信号状态
    je reschedule
ret_from_sys_call:
    movl current,%eax       # task[0] cannot have signals
    cmpl task,%eax
    je 3f
    cmpw $0x0f,CS(%esp)     # was old code segment supervisor ?
    jne 3f
    cmpw $0x17,OLDSS(%esp)      # was stack segment = 0x17 ?
    jne 3f
    movl signal(%eax),%ebx
    movl blocked(%eax),%ecx
    notl %ecx
    andl %ebx,%ecx
    bsfl %ecx,%ecx
    je 3f
    btrl %ecx,%ebx
    movl %ebx,signal(%eax)
    incl %ecx
    pushl %ecx
    call do_signal
    popl %eax
3:  popl %eax
    popl %ebx
    popl %ecx
    popl %edx
    pop %fs
    pop %es
    pop %ds
    iret

我们可以发现,上面代码中大部分代码是寄存器状态保存与恢复,堆栈段的切换。核心代码为call sys_call_table(,%eax,4),它是一个函数调用,函数的地址为sys_call_table(,%eax,4) = sys_call_table + 4*%eax说明sys_call_table为一个数组入口,数组中的元素长度都为4个字节,我们要访问数组中的第%eax个元素。而%eax即为系统调用号。sys_call_table就是所有系统调用的函数指针数组。

// 定义在 linux/include/linux/sys.h
fn_ptr sys_call_table[] = { sys_setup, sys_exit, sys_fork, sys_read,
sys_write, sys_open, sys_close, sys_waitpid, sys_creat, sys_link,
sys_unlink, sys_execve, sys_chdir, sys_time, sys_mknod, sys_chmod,
sys_chown, sys_break, sys_stat, sys_lseek, sys_getpid, sys_mount,
sys_umount, sys_setuid, sys_getuid, sys_stime, sys_ptrace, sys_alarm,
sys_fstat, sys_pause, sys_utime, sys_stty, sys_gtty, sys_access,
sys_nice, sys_ftime, sys_sync, sys_kill, sys_rename, sys_mkdir,
sys_rmdir, sys_dup, sys_pipe, sys_times, sys_prof, sys_brk, sys_setgid,
sys_getgid, sys_signal, sys_geteuid, sys_getegid, sys_acct, sys_phys,
sys_lock, sys_ioctl, sys_fcntl, sys_mpx, sys_setpgid, sys_ulimit,
sys_uname, sys_umask, sys_chroot, sys_ustat, sys_dup2, sys_getppid,
sys_getpgrp, sys_setsid, sys_sigaction, sys_sgetmask, sys_ssetmask,
sys_setreuid,sys_setregid };

到这里,我们找到了最终真正的执行核心函数地址sys_write,这个是操作实现的内核代码,所有的屏幕打印就是由该函数最终实现。它里面涉及IO的一些硬件驱动函数,我们在这里就不再继续深入了。

到此,我们已经通过printf这样一个上层的函数接口,清楚操作系统是如何一步步为了我们提供了一个内核调用的方法。如此的精细控制,让人感叹。

4. 我们如何为操作系统添加一个系统调用

下面简单说明一下,如何在操作系统源码中添加两个我们自己的系统调用whoami和iam

  • iam系统调用把我们指定的一个字符串保存在内核中。
  • whoami把内核中的通过iam设置的那个字符串读取出来。

下面是具体的操作步骤。

  • 在linux/kernel文件夹加入一个自定义的文件who.c
  • 在who.c中实现sys_iam和sys_whoami,需要注意的实现这两个函数时,需要用于用户栈数据与内核栈数据拷贝。
  • 在linux/include/linux/sys.h中的sys_call_table中添加两个数组项。
  • 修改linux/kernel/system_call.s中的系统调用个数nr_system_calls。
  • 用int 0x80实现iam和whoami函数。
  • 编写用户程序调用上面两个函数。

要注意的是:在系统调用的过程中,段寄存器ds和es指向内核数据空间,而fs被设置指向用户数据空间。因此在实际数据块信息传递过程中Linux内核就可以利用fs寄存器来执行内核数据空间与用户数据空间之间的数据复制工作,并且在复制过程中内核程序不需要对数据边界范围作任何检查操作。边界检查操作由CPU自动完成。内核程序的实际数据传送工作可以使用get_fs_byte()和puts_fs_bypte()等函数进行。

php模拟linux crontab实现定时计划任务的方法

本文分享一下php模拟linux crontab实现定时计划任务的方法。

PHP定时计划任务需要两个文件。

1、crontab.conf.php (配置文件)

<?php
//当为0时,关闭计划任务
return 1;

2、crontab.php (主体文件)

<?php
ignore_user_abort();//关掉浏览器,PHP脚本也可以继续执行.
set_time_limit(0);// 通过set_time_limit(0)可以让程序无限制的执行下去

$interval = 60 * 3;// 每隔3分钟运行
$i = 0;

do {
    $nowTime = date("Y-m-d H:m:s");
    $run = include 'crontab.conf.php';

    if (!$run) {
        file_put_contents("crontab_task.log", "==计划任务已结束 $nowTime==rn", FILE_APPEND);
        die('Job has ended.');
    }

    //此处放要执行的代码
    sleep($interval);// 等待3分钟
    $data = "$i>计划任务正在运行中...(运行状态:$run)  $nowTimern";
    file_put_contents("tasktest.txt", $data, FILE_APPEND);
    $i++;
} while (true);

主要改变 crontab.conf.php 中 return 0 即可实现控制这个计划任务的关闭。

注意:当php服务关掉之后该计划任务脚本也会停掉并且不会自动重启。