系统管理工具
- 进程的分类:
CPU-Bound:CPU密集型,非交互。特别消耗CPU的,加密解密,压缩解压
IO-Bound:IO密集型,交互。大量的硬盘读写,例如复制文件
- Linux系统状态的查看及管理工具:pstree, ps, pidof, pgrep, top, htop, glance, pmap, vmstat, dstat, kill, pkill, job, bg, fg, nohup
- pstree命令:
pstree – display a tree of processes 显示进程的树状结构
- ps: process state 进程状态。
ps – report a snapshot of the current processes 显示进程的当前状态
Linux系统各进程的相关信息均保存在/proc/PID目录下 的各文件中
每个进程都有唯一编号,每个数字的文件夹都对应着一个进程的编号。
[root@localhost ~]# ls /proc/
1 15 1822 2042 274 419 540 619 991 iomem sched_debug
10 1532 1823 2044 275 426 542 639 992 ioports schedstat
1005 1547 1878 2070 276 427 546 654 993 irq scsi
1011 1554 1883 2134 277 428 565 657 999 kallsyms self
1012 1555 1889 2148 278 429 566 675 acpi kcore slabinfo
1072 16 1897 2168 279 487 567 7 asound keys softirqs
pstree 不加 -p选项只显示进程的名称,加 -p可以显示出进程的编号
[root@localhost ~]# pstree
[root@localhost ~]# pstree -p
pstree显示进程的名称
[root@localhost /etc/selinux]# pstree
init─┬─NetworkManager─┬─dhclient
│ └─{NetworkManager} 表示线程
进程:一个进程肯定有一个线程,一个进程也可以有多个线程。
进程相当于一个项目组,承担了一个工作,项目简单一个人能够完成,项目成员就一个人,就变现为一个线程,项目比较复杂,如果一个人干不了,需要多个人共同协作,这时候就表现为多个线程。进程和线程的关系相当于项目组合项目成员的关系。 一个人,就是一个线程,多个人,就是多个线程,每个线程相当于一个人。每个人和其他项目小组中的同一个小组中的其他人之间互相之间可以协作完成一些任务,各自是独立运行的,这就是多线程。
多进程和多线程是两码事。进程和进程之间是相互隔断的。
进程和进程之间相当于两个项目小组之间的关系,各干各的活。一个进程里面多个线程之间因为为了完成同一个任务,只不过每个人扶着其中的一小部分工作,相互之间有协作关系。
线程:
在Linux中有些服务就是多线程的,但是不是必须的,可以调整。
[root@localhost ~]# service httpd start
[root@localhost ~]# pstree -p
init(1)─┬─NetworkManager(1654)─┬─dhclient(1718)
│ └─{NetworkManager}(1719)
├─httpd(4573)─┬─httpd(4576)
│ ├─httpd(4577)
│ ├─httpd(4578)
│ ├─httpd(4579)
│ ├─httpd(4580)
│ ├─httpd(4581)
│ ├─httpd(4582)
│ └─httpd(4583)
一个主进程8个子进程。也可以以线程的方式。一个主进程,在开若干个子进程,每个子进程中在开若干个线程
[root@localhost ~]# vim /etc/sysconfig/httpd
[root@localhost ~]# service httpd restart
[root@localhost ~]# pstree -p
HTTPD=/usr/sbin/httpd.worker 去掉注释
每个线程是可以独立工作的。线程和线程之间,在同一个进程中是共享内存空间的。如果一个线程错故障了,可能会影响统一进程中的其他线程,因为是共享内存空间的
显示某个用户的进程
pstree -p ding
在CnetOS7中查看某个进程的子进程:
[root@localhost ~]# pstree -ps 1
[root@localhost ~]# pstree -ps 992
systemd(1)───sshd(992)─┬─sshd(1532)───bash(1555)
└─sshd(8251)───bash(8259)───pstree(8884)
只看和指定进程的父子关系,显示出上级进程、下级进程的关系。在6上不支持
高亮显示:
[root@localhost ~]# pstree -psH 992
ps默认只显示当前终端中运行的进程,就是当前用户开启的进程
查看进程进程ps
- ps [OPTION]…
- 支持三种选项:
UNIX选项 如-A -e 必须有一个 dash( – )开头的
BSD选项 如a 伯克利大学流派,没有 ( – )
GNU选项 如–help 两个( – )
- 选项:默认显示当前终端中的进程
a 选项包括所有终端中的进程
x 选项包括不链接终端的进程
u 选项显示进程所有者的信息
f 选项显示进程树,相当于 –forest
k|–sort 属性 对属性排序,属性前加- 表示倒序
o 属性… 选项显示定制的信息 pid、cmd、%cpu、%mem
L 显示支持的属性列表
显示所有终端开启的进程
[root@localhost ~]# ps a
PID TTY STAT TIME COMMAND
1555 pts/0 Ss+ 0:00 -bash
8259 pts/1 Ss 0:00 -bash
8750 pts/2 Ss 0:00 bash
8832 pts/2 S+ 0:00 vim a
9021 pts/1 R+ 0:00 ps a
显示和终端无关的进程,开机的时候就已经启动了,和终端无关
[root@localhost ~]# ps ax
PID TTY STAT TIME COMMAND
1 ? Ss 0:05 /usr/lib/systemd/systemd
2 ? S 0:00 [kthreadd]
3 ? S 0:00 [ksoftirqd/0]
5 ? S< 0:00 [kworker/0:0H]
显示进程谁在运行。把进程的运行身份显示出来
[root@localhost ~]# ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.4 128164 4940 ? Ss 03:10 0:05 /usr/lib/systemd/systemd –switched-root –syst
root 2 0.0 0.0 0 0 ? S 03:10 0:00 [kthreadd]
USER用户
PID
%CPU 占用的CPU
%MEM 占用的内存
VSZ 占的虚拟内存是多大。 虚拟内存是操作系统承诺分配给应用程序的内存。包括物理上的内存和swap上的内存。
RSS 占的实际内存是多大,真正分配给应用程序的内存
TTY 终端
STAT 状态
START 什么时候开始运行的
TIME 时间片的累积值
COMMAND 正在执行的程序
类似于ps aux的,不如aux多
[root@localhost ~]# ps -ef
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 03:10 ? 00:00:05 /usr/lib/systemd/systemdroot 2 0 0 03:10 ? 00:00:00 [kthreadd]
root 3 2 0 03:10 ? 00:00:00 [ksoftirqd/0]
C:表示CPU的利用率
-e 类似于 -A,等价的
显示进程树
[root@localhost ~]# ps auxf
父进程被杀死,子进程就没了
挑一部字段分显示
[root@localhost ~]# ps axo pid,cmd,%cpu
PID CMD %CPU
1 /usr/lib/systemd/systemd — 0.0
2 [kthreadd] 0.0
3 [ksoftirqd/0] 0.0
默认按照PID进行显示,按照cpu利用率排序
[root@localhost ~]# ps axo pid,cmd,%cpu –sort %cpu 长格式
PID CMD %CPU
1 /usr/lib/systemd/systemd — 0.0
[root@localhost ~]# ps axo pid,cmd,%cpu k %cpu 短格式
PID CMD %CPU
1 /usr/lib/systemd/systemd — 0.0
注意:在CentOS6上按照内存排序会有问题
关闭图形界面
[root@localhost ~]# ps axo pid,cmd,%cpu,%mem k %mem
PID CMD %CPU %MEM
657 /usr/bin/python -Es /usr/sb 0.0 2.7
9588 /usr/bin/gnome-shell 25.0 5.8
[root@localhost ~]# free -h
total used free shared buff/cache available
Mem: 976M 305M 283M 10M 387M 462M
Swap: 2.0G 3.9M 2.0G
[root@localhost ~]# init 3
[root@localhost ~]# free -h
total used free shared buff/cache available
Mem: 976M 194M 396M 10M 385M 575M
Swap: 2.0G 3.9M 2.0G
[root@localhost ~]# ps axo pid,cmd,%cpu,%mem k %mem
PID CMD %CPU %MEM
798 /sbin/dhclient -d -q -sf /u 0.0 1.5
657 /usr/bin/python -Es /usr/sb 0.0 2.7
显示支持的属性列表
[root@localhost ~]# ps L
%cpu %CPU
%mem %MEM
ps常见选项
- -C cmdlist 指定命令,多个命令用“ , ”分隔
- -L 显示线程
- -e: 显示所有进程,相当于-A
- -f: 显示完整格式程序信息
- -F: 显示更完整格式的进程信息
- -H: 以进程层级格式显示进程相关信息
- -u userlist 指定有效的用户ID或名称
- -U userlist 指定真正的用户ID或名称
- -g gid或groupname 指定有效的gid或组名称
- -G gid或groupname 指定真正的gid或组名称
- -p pid 显示指pid的进程
- –ppid pid 显示属于pid的子进程
- -M 显示SELinux信息,相当于Z
-C 显示指定程序的名称。相当于过滤
[root@localhost ~]# ps -C bash
PID TTY TIME CMD
4430 pts/1 00:00:00 bash
5217 pts/2 00:00:00 bash
5268 tty2 00:00:00 bash
细节:
终端A:
[root@localhost ~]# vim sl.sh
[root@localhost ~]# chmod +x sl.sh
[root@localhost ~]# cat sl.sh
#!/bin/bash
sleep 300
[root@localhost ~]# ./sl.sh
终端B:
[root@localhost ~]# ps -C sl.sh
PID TTY TIME CMD
5594 pts/1 00:00:00 sl.sh
如果不写#!/bin/bash,再次执行
[root@localhost ~]# ps -C sl.sh
PID TTY TIME CMD
不写 #!/bin/bash或者直接使用bash运行的程序,ps 中的 -C选项无法查询出来
[root@localhost ~]# bash sl.sh
[root@localhost ~]# w 在bash上面运行的
root pts/1 172.18.0.100 23:41 3.00s 0.47s 0.00s bash sl.sh
混用的时候可能会产生冲突
[root@localhost ~]# ps -C sl.sh,vim,init axo pid,cmd,%mem
PID CMD %MEM
1 /sbin/init 0.1
2 [kthreadd] 0.0
3 [migration/0] 0.0
-C sl.sh,vim,init不起作用
[root@localhost ~]# ps -C sl.sh,vim,init o pid,cmd,%mem
PID CMD %MEM
1 /sbin/init 0.1
5236 vim a 0.4
5296 vim abc 0.4
5572 vim abc 0.4
5884 /bin/bash ./sl.sh 0.1
显示线程
[root@localhost ~]# ps -Lef
root 5730 1 5730 0 1 00:59 ? 00:00:00 /usr/sbin/httpd.worker
apache 5851 5730 5851 0 27 01:00 ? 00:00:00 /usr/sbin/httpd.worker
……
-F 显示更完整格式的进程信息
[root@localhost ~]# ps -eF
UID PID PPID C SZ RSS PSR STIME TTY TIME CMD
root 1 0 0 4838 1556 0 Dec15 ? 00:00:02 /sbin/init
root 2 0 0 0 0 0 Dec15 ? 00:00:00 [kthreadd]
root 3 2 0 0 0 0 Dec15 ? 00:00:00 [migration/0]
PPID C
SZ
RSS
PSR 内核,进程是运行在哪个CPU上的
STIME TTY TIME CMD
运行的进程会在内核间切换
- -u userlist 指定有效的用户ID或名称,生效的用户
- -U userlist 指定真正的用户ID或名称,发起进程执行者的身份
例如普通用户执行passwd命令。发起程序的运行者是普通用户,生效的用户是root
-u看到的是生效的用户
互斥的选项:ps -C passwd -u root
显示指定pid的进程。进程和进程编号,属性的组合
[root@localhost ~]# ps -p 992 o pid,cmd,%cpu
PID CMD %CPU
992 /usr/sbin/sshd -D 0.0
[root@localhost ~]# ps -C passwd o pid,cmd,%cpu
PID CMD %CPU
显示属于pid的子进程
[root@localhost ~]# ps –ppid 5730
PID TTY TIME CMD
5851 ? 00:00:00 httpd.worker
ps输出属性
- VSZ: Virtual memory SiZe,虚拟内存集,线性内存。承诺分配的虚拟内存,不是真的分配
- RSS: ReSident Size, 常驻内存集,真正分配的内存
- STAT:进程状态
R:running
S: interruptable sleeping 可唤醒的休眠
D: uninterruptable sleeping 不可唤醒的休眠
T: stopped 暂停的,可以唤醒
Z: zombie 僵死的
+: 前台进程
l: 多线程进程
L:内存分页并带锁
N:低优先级进程
<: 高优先级进程
s: session leader,会话(子进程)发起者
ps
- ni: nice值
- pri: priority 优先级
- psr: processor CPU编号
- rtprio: 实时优先级
- 示例:
ps axo pid,cmd,psr,ni,pri,rtprio
- 常用组合:
aux
-ef
-eFH
-eo pid,tid,class,rtprio,ni,pri,psr,pcpu,stat,comm
axo stat,euid,ruid,tty,tpgid,sess,pgrp,ppid,pid,pcpu,comm [挑一些字段来显示]
查看优先级
[root@localhost ~]# ps axo pid,cmd,ni
PID CMD NI
1 /usr/lib/systemd/systemd — 0
2 [kthreadd] 0
3 [ksoftirqd/0] 0
值越大优先级越差
查看进程优先级和CPU利用率
[root@localhost ~]# ps axo pid,cmd,ni,%cpu
[root@localhost ~]# ps axo pid,cmd,ni,%cpu
PID CMD NI %CPU
1 /usr/lib/systemd/systemd — 0 0.6
调整优先级
[root@localhost ~]# renice -n -20 2543
2543 (process ID) old priority 0, new priority -20
[root@localhost ~]# ps axo pid,cmd,%cpu,ni
2543 ping 172.18.0.100 0.0 -20
-n选项也可以不加
[root@localhost ~]# renice -10 2543
2543 (process ID) old priority -20, new priority -10
[root@localhost ~]# renice 10 2543
2543 (process ID) old priority -10, new priority 10
指定以多少优先级运行命令
[root@localhost ~]# nice -n -5 ping 172.18.0.100
[root@localhost ~]# ps -axo pid,cmd,%cpu,ni
2639 ping 172.18.0.100 0.0 -5
renice是程序已经运行起来,后期去调整,nice是运行命令的时候就指定运行的优先级
[root@localhost ~]# nice -5 ping 172.18.0.100
[root@localhost ~]# ps -axo pid,cmd,%cpu,ni
2693 ping 172.18.0.100 0.0 5
2701 sleep 60 0.0 0
2702 ps -axo pid,cmd,%cpu,ni 0.0 0
[root@localhost ~]# nice -11 ping 172.18.0.100
[root@localhost ~]# ps -axo pid,cmd,%cpu,ni
2703 ping 172.18.0.100 0.0 11
[root@localhost ~]# nice –11 ping 172.18.0.100
[root@localhost ~]# ps -axo pid,cmd,%cpu,ni
2714 ping 172.18.0.100 0.0 -11
[root@localhost ~]# which nice
/usr/bin/nice
[root@localhost ~]# rpm -qf /usr/bin/nice
coreutils-8.22-18.el7.x86_64
查看pri的优先级
[root@localhost ~]# nice -n 10 ping 127.0.0.1
[root@localhost ~]# ps axo pid,cmd,%cpu,ni,%mem,pri
2828 ping 127.0.0.1 0.0 10 0.1 9
[root@localhost ~]# nice -n -10 ping 127.0.0.1
[root@localhost ~]# ps axo pid,cmd,%cpu,ni,%mem,pri
2830 ping 127.0.0.1 0.0 -10 0.1 29
终端A:[root@localhost ~]# nice -n 10 ping 127.0.0.1
终端B:[root@localhost ~]# nice -n -10 ping 127.0.0.1
[root@localhost ~]# ps axo pid,cmd,%cpu,ni,%mem,pri
2895 ping 127.0.0.1 0.0 -10 0.1 29
2896 ping 127.0.0.1 0.0 10 0.1 9
[root@localhost ~]# ps -C ping o pid,cmd,ni,%cpu,pri
PID CMD NI %CPU PRI
2940 ping 127.0.0.1 -10 0.0 29
2941 ping 127.0.0.1 10 0.0 9
pri值越大优先级越高,nice值越小优先级越高,范围是-20 – 19
[root@localhost ~]# nice -n 30 ping 127.0.0.1
[root@localhost ~]# ps -C ping o pid,cmd,ni,%cpu,pri
PID CMD NI %CPU PRI
2941 ping 127.0.0.1 10 0.0 9
3037 ping 127.0.0.1 19 0.0 0
[root@localhost ~]# nice -n -20 ping 127.0.0.1
[root@localhost ~]# ps -C ping o pid,cmd,ni,%cpu,pri
PID CMD NI %CPU PRI
2941 ping 127.0.0.1 10 0.0 9
3039 ping 127.0.0.1 -20 0.0 39
实时优先级对应于前一部分,nice对应于系统优先级的后一部分。nice优先级又被称为动态优先级,表面上给它设置了优先级,但运行的时候会根据系统的实际情况,自动的去调整优先级。系统的内核可能会去做一个相应的微调。realtime是固定优先级,设置好之后就固定不变了
[root@localhost ~]# ps -C ping o pid,cmd,ni,%cpu,pri,rtprio
PID CMD NI %CPU PRI RTPRIO
2941 ping 127.0.0.1 10 0.0 9 –
3119 ping 127.0.0.1 -20 0.0 39 –
[root@localhost ~]#
nice优先级不对应实时优先级,nice优先级和realtime没有任何的对应关系。
查看实时优先级
[root@localhost ~]# ps axo pid,cmd,ni,%cpu,pri,rtprio
PID CMD NI %CPU PRI RTPRIO
7 [migration/0] – 0.0 139 99
10 [watchdog/0] – 0.0 139 99 看门狗,监控内核状态的
pri值越大优先级越高。
pri的优先级和系统的优先级是反着来划的,pri的优先级是139-0,139最大,系统优先级是0-139,0最大
查看有效用户和真正用户
[ding@localhost ~]$ passwd
Changing password for user ding.
Changing password for ding.
(current) UNIX password:
[root@localhost ~]# ps axo pid,cmd,ni,%cpu,euid,ruid euid 和 uid一样
[root@localhost ~]# ps axo pid,cmd,ni,%cpu,uid,ruid
3275 passwd 0 0.0 0 1000
有效用户:uid,运行进程用户的uid
真正用户:ruid,发起进程用户的uid
ps示例
- 查询你拥有的所有进程:
ps -x
- 显示指定用户名(RUID)或用户ID的进程:
ps -fU apache 用户名
ps -fu 48 用户的UID
(RUID)真实用户
- 显示指定用户名(EUID)或用户ID的进程:
ps -fu wang
ps -fu 1000
(EUID)有效用户
- 查看以root用户权限(实际和有效ID)运行的每个进程:
ps -U root -u root
- 列出某个组拥有的所有进程(实际组ID:RGID或名称):
ps -fG nginx
显示所有和终端无连接的进程
[root@localhost ~]# ps x
PID TTY STAT TIME COMMAND
查询你拥有的所有进程
[root@localhost ~]# ps -x 显示的是有效用户的进程
显示指定用户名(RUID)或用户ID的进程
可以是UID,也可以是用户名
[ding@localhost ~]$ ps -fu ding 程序的发起者
UID PID PPID C STIME TTY TIME CMD
ps示例
- 列出有效组名称(或会话)所拥有的所有进程:
ps -fg mysql
ps -fG 27
- 通过进程ID来显示所属的进程:
ps -fp 1234
- 以父进程ID来显示其下所有的进程,如显示父进程为1154的所有进程:
ps -f –ppid 1234
- 显示指定PID的多个进程:
ps -fp 1204,1239,1263
- 要按tty显示所属进程:
ps -ft pst/0
通过进程编号显示进程的详细信息
[root@localhost ~]# ps -fp 946
UID PID PPID C STIME TTY TIME CMD
root 946 1 0 16:42 ? 00:00:00 /usr/sbin/sshd -D
显示指定进程下的子进程
[root@localhost ~]# pstree -p
systemd(1)─┬─ModemManager(581)─┬─{ModemManager}(614)
├─sshd(946)─┬─sshd(2376)───bash(2385)───pstree(3557)
│ ├─sshd(2439)───bash(2445)───su(3427)───bash(3428)
│ └─sshd(2848)───bash(2853)
[root@localhost ~]# ps -f –ppid 946
UID PID PPID C STIME TTY TIME CMD
root 2376 946 0 16:44 ? 00:00:00 sshd: root@pts/1
root 2439 946 0 16:46 ? 00:00:00 sshd: root@pts/2
root 2848 946 0 17:05 ? 00:00:00 sshd: root@pts/3
[root@localhost ~]# ps -f –ppid 2439
UID PID PPID C STIME TTY TIME CMD
root 2445 2439 0 16:46 pts/2 00:00:00 -bash
ps示例
- 以进程树显示系统中的进程如何相互链接:
ps -e –forest
- 以进程树显示指定的进程
ps -f –forest -C sshd
ps -ef –forest | grep -v grep | grep sshd
- 要显示一个进程的所有线程,将显示LWP(轻量级进程)以及 NLWP(轻量级进程数)列:
ps -fL -C nginx
- 要列出所有格式说明符:
ps L
- 查看进程的PID,PPID,用户名和命令:
ps -eo pid,ppid,user,cmd
以进程树显示系统中的进程如何相互链接:
[root@localhost ~]# ps -e –forest
PID TTY TIME CMD
2 ? 00:00:00 kthreadd
3 ? 00:00:00 \_ ksoftirqd/0
要显示一个进程的所有线程,将显示LWP(轻量级进程)以及 NLWP(轻量级进程数)列
[root@localhost ~]# ps -fL -C httpd.worker
UID PID PPID LWP C NLWP STIME TTY TIME CMD
root 2897 1 2897 0 1 08:22 ? 00:00:00 /usr/sbin/httpd.worker
apache 3014 2897 3014 0 27 08:22 ? 00:00:00 /usr/sbin/httpd.worker
apache 3014 2897 3016 0 27 08:22 ? 00:00:00 /usr/sbin/httpd.worker
apache 3014 2897 3017 0 27 08:22 ? 00:00:00 /usr/sbin/httpd.worker
apache 3014 2897 3018 0 27 08:22 ? 00:00:00 /usr/sbin/httpd.worker
ps示例
- 自定义格式显示文件系统组,ni值开始时间和进程的时间:
ps -p 1234 -o pid,ppid,fgroup,ni,lstart,etime
lstart:启动时间
- 使用其PID查找进程名称:
ps -p 1244 -o comm=
- 要以其名称选择特定进程,显示其所有子进程
ps -C sshd,bash
- 查找指定进程名所有的所属PID,在编写需要从std输出或文件读取PID的脚本时这个参数很有用:
ps -C httpd,sshd -o pid=
- 检查一个进程的执行时间 ps -eo comm,etime,user | grep nginx
查看进程名称
[root@localhost ~]# ps -p 1 -o comm=
init
[root@localhost ~]# ps -p 1 -o comm=
systemd
显示进程编号
[root@localhost ~]# ps -C httpd,sshd -o pid=
2017
2380
2808
[root@localhost ~]# ps -C httpd.worker -o pid=
2897
3014
查看一个进程的执行时间 etime:执行时间
[root@localhost ~]# ps -eo comm,etime,user | grep httpd
httpd.worker 07:33 root
httpd.worker 07:28 apache
ps示例
- 查找占用最多内存和CPU的进程:
ps -eo pid,ppid,cmd,%mem,%cpu –sort=-%mem | head ps -eo pid,ppid,cmd,%mem,%cpu –sort=-%cpu | head
-%cpu表示倒序
- 显示安全信息: ps -eM ps –context
- 使用以下命令以用户定义的格式显示安全信息
ps -eo euser,ruser,suser,fuser,f,comm,label
- 使用watch实用程序执行重复的输出以实现对就程进行实时的监视,如下面的命令显示每秒钟的监视:
watch -n 1 ‘ps -eo pid,ppid,cmd,%mem,%cpu –sort=%mem | head’
查看占用内存最大的进程
[root@localhost ~]# ps -eo pid,ppid,cmd,%mem,%cpu –sort=-%mem
PID PPID CMD %MEM %CPU
1694 1475 /usr/bin/gnome-shell 15.9 0.1
1915 1 /usr/libexec/evolution-cale 6.0 0.0
2126 1915 /usr/libexec/evolution-cale 5.9 0.0
每秒排序一次,显示前10个内存占用最高的进程
[root@localhost ~]# dd if=/dev/zero of=/dev/null bs=1G
[root@localhost ~]# watch -n 1 ‘ps -eo pid,ppid,cmd,%mem,%cpu –sort=-%mem | head’
本文来自投稿,不代表Linux运维部落立场,如若转载,请注明出处:http://www.178linux.com/90334