404频道

学习笔记

本文为Linux设备驱动程序的入门实践文章,编写一个hello world程序,并在Linux上执行。

编写驱动程序

驱动程序hello.c文件内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#ifndef __KERNEL__
# define __KERNEL__
#endif
#ifndef MODULE
# define MODULE
#endif

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>

MODULE_LICENSE("GPL");

int hello_init()
{
printk(KERN_WARNING "Hello kernel!\n");
return 0;
}


void hello_exit()
{
printk("Bye, kernel!\n");
}

module_init(hello_init);
module_exit(hello_exit)

编写Makefile

Makefile文件的写法可以采用传统的make方式,也可以采用kbuild的方式。

采用传统的make方式的写法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
ifeq ($(KERNELRELEASE),)
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)

modules:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules

modules_install:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install

clean:
rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions

.PHONY: modules modules_install clean
else
obj-m := hello.o
endif

采用kbuild方式的Makefile内容如下:

1
2
3
4
5
6
7
obj-m := hello.o

all :
$(MAKE) -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

clean:
$(MAKE) -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

编译

将hello.c和Makefile文件放在任意目录中,执行make命令编译。

安装

执行insmod hello.ko命令安装驱动程序,通过lsmod命令即可看到驱动程序已经安装。

通过查看/var/log/messages文件即可看到hello驱动程序打印的内容。

卸载

执行rmmod hello.ko命令即可卸载驱动程序模块。

参考文章

《深入理解Linux设备驱动程序》
《Linux那些事之我是USB》
Ubuntu12.10 内核源码外编译 linux模块–编译驱动模块的基本方法

本文仅为了练习Linux内核源码的编译安装,安装环境为VMWare下的CentOS,现有CentOS版本为2.6.32-358.el6.x86_64
/boot/grub/grub.conf文件内容如下:

1
2
3
4
5
6
7
8
9
# 注释部分去掉
default=0
timeout=5
splashimage=(hd0,0)/grub/splash.xpm.gz
hiddenmenu
title CentOS (2.6.32-358.el6.x86_64)
root (hd0,0)
kernel /vmlinuz-2.6.32-358.el6.x86_64 ro root=/dev/mapper/vg_livedvd-lv_root rd_NO_LUKS rd_LVM_LV=vg_livedvd/lv_root rd_NO_MD crashkernel=auto rd_LVM_LV=vg_livedvd/lv_swap KEYBOARDTYPE=pc KEYTABLE=us rd_NO_DM LANG=zh_CN.UTF-8 rhgb quiet
initrd /initramfs-2.6.32-358.el6.x86_64.img

获取内核源码

首先从Linux的官方网站下载最新版内核Linux3.13。

执行tar Jxvf linux-3.13.tar.xz -C/usr/src/kernels命令将内核源码解压到内核源代码存放目录/usr/src/kernels/,该源码目录并不固定,但推荐将内核源码存放到该目录下。

为了将上次编译时的目标文件及相关设置文件删除,执行make mrproper

挑选功能

可以采用了多种方式,这里采用make menuconfig的方式来挑选内核功能,该方式不需要X Window(make xconfig方式)的支持,而且要比纯命令行方式(make config)要直观。执行make menuconfig遇到如下错误:

1
2
3
4
5
6
7
8
9
10
11
[root@localhost linux-3.13]# make menuconfig
HOSTCC scripts/basic/fixdep
HOSTCC scripts/kconfig/conf.o
*** Unable to find the ncurses libraries or the
*** required header files.
*** 'make menuconfig' requires the ncurses libraries.
***
*** Install ncurses (ncurses-devel) and try again.
***
make[1]: *** [scripts/kconfig/dochecklxdialog] 错误 1
make: *** [menuconfig] 错误 2

这是因为需要ncurses库的支持,下面采用从源码安装的方式安装ncurses。

从ncurses的官方网站下载最新版的ncurses-5.9.tar.gz。然后分别执行./configure、makemake install`命令安装。

更改内核版本号标识

为了能够在编译完成后的内核版本中通过uname -r看到定义的内核版本号,修改Makefile文件。其中EXTRAVERSION字段值为空,将其赋值为kuring。

编译内核

执行make命令,该过程需要话费很长时间,我在512MB的VM下跑,花费了大约1个半小时时间。

编译内核模块

执行make modules命令。

安装内核模块

执行make modules_install命令,会将内核模块安装到/lib/modules目录下。

安装内核

执行make install命令,产生如下输出:

1
2
3
4
5
6
sh /usr/src/kernels/linux-3.13/arch/x86/boot/install.sh 3.13.0kuring arch/x86/boot/bzImage \
System.map "/boot"
ERROR: modinfo: could not find module vmhgfs
ERROR: modinfo: could not find module vsock
ERROR: modinfo: could not find module vmware_balloon
ERROR: modinfo: could not find module vmci

这个错误跟vmware的vmware tools有关,暂时不去管。

这样再去看/boot/grub/grub.conf文件,会看到文件已经变化,已经将新内核添加到开机启动项中。

1
2
3
4
5
6
7
8
9
10
11
12
13
# 注释部分去掉
default=1
timeout=5
splashimage=(hd0,0)/grub/splash.xpm.gz
hiddenmenu
title CentOS (3.13.0kuring)
root (hd0,0)
kernel /vmlinuz-3.13.0kuring ro root=/dev/mapper/vg_livedvd-lv_root rd_NO_LUKS rd_LVM_LV=vg_livedvd/lv_root rd_NO_MD crashkernel=auto rd_LVM_LV=vg_livedvd/lv_swap KEYBOARDTYPE=pc KEYTABLE=us rd_NO_DM LANG=zh_CN.UTF-8 rhgb quiet
initrd /initramfs-3.13.0kuring.img
title CentOS (2.6.32-358.el6.x86_64)
root (hd0,0)
kernel /vmlinuz-2.6.32-358.el6.x86_64 ro root=/dev/mapper/vg_livedvd-lv_root rd_NO_LUKS rd_LVM_LV=vg_livedvd/lv_root rd_NO_MD crashkernel=auto rd_LVM_LV=vg_livedvd/lv_swap KEYBOARDTYPE=pc KEYTABLE=us rd_NO_DM LANG=zh_CN.UTF-8 rhgb quiet
initrd /initramfs-2.6.32-358.el6.x86_64.img

同时在/boot目录下已经多出了vmlinuz-3.13.0kuring、System.map-3.13.0kuring、initramfs-3.13.0kuring.img文件。

重启系统后,在启动菜单中多出了新内核选项。进入新内核后,执行uname -r显示3.13.0kuring,说明新内核已经安装完成。

在用CentOS默认的svn客户端工具访问Windows下搭建的subversion时会提示如下错误:

1
2
[kuring@localhost 桌面]$ svn checkout https://192.168.100.100/svn/test
svn: 方法 OPTIONS 失败于 “https://192.168.100.100/svn/test: SSL handshake failed: SSL 错误:Key usage violation in certificate has been detected. (https://192.168.100.100)

通过执行如下命令可以看到svn是支持https协议的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[kuring@localhost ~]$ svn --version
svn,版本 1.6.11 (r934486)
编译于 Apr 11 2013,16:13:51

版权所有 (C) 2000-2009 CollabNet。
Subversion 是开放源代码软件,请参阅 http://subversion.tigris.org/ 站点。
此产品包含由 CollabNet(http://www.Collab.Net/) 开发的软件。

可使用以下的版本库访问模块:

* ra_neon : 通过 WebDAV 协议使用 neon 访问版本库的模块。
- 处理“http”方案
- 处理“https”方案
* ra_svn : 使用 svn 网络协议访问版本库的模块。 - 使用 Cyrus SASL 认证
- 处理“svn”方案
* ra_local : 访问本地磁盘的版本库模块。
- 处理“file”方案

这是由于svn客户端在https协议中使用了GnuTLS库造成的,将其更改为使用openssl库即可。通过执行如下命令可以查看svn使用的库:

1
2
3
[kuring@localhost bin]$ ldd svn | grep ssl
[kuring@localhost bin]$ ldd svn | grep tls
libgnutls.so.26 => /usr/lib64/libgnutls.so.26 (0x00007f33004ad000)

下面选择重新编译的方式来安装svn。

删除subversion

执行:yum remove subversion

检查openssl安装情况

这里已经安装:

1
2
3
[kuring@localhost tmp]$ rpm -qa | grep openssl
openssl-1.0.1e-15.el6.x86_64
openssl-devel-1.0.1e-15.el6.x86_64

安装neon

这里选择的安装版本为0.29.6,subversion对neon的版本有要求。如果不是subversion的版本,在执行subversion下的configure文件时并不会报错

1
2
3
4
5
[kuring@localhost software]$ tar zvxf neon-0.29.6.tar.gz
[kuring@localhost software]$ cd neon-0.29.6
./configure --with-ssl=openssl
make
make install

安装apr

1
2
3
4
5
tar zvxf apr-1.5.0.tar.gz
cd apr-1.5.0
./configure
make
make install

安装apr-util

1
2
3
4
5
tar zvxf apr-util-1.5.3.tar.gz 
cd apr-util-1.5.3
./configure --with-apr=/usr/local/apr
make
make install

下载sqllite

1
2
3
unzip sqlite-amalgamation-3080401.zip
mv sqlite-amalgamation-3080401 sqlite-amalgamation
mv sqlite-amalgamation subversion-1.8.8/ // 将其复制到subversion源码目录下

安装subversion

1
2
3
4
tar zvxf subversion-1.7.16.tar.gz
./configure --with-ssl --with-neon --with-apr=/usr/local/apr --with-apr-util=/usr/local/apr
make
make install

然后再执行svn --version命令可以看到已经包含了https协议。

参考资料

SSL handshake failed: SSL error: Key usage violation in certificate has been detected CentOS

资料下载

需要的安装包下载

从官方网站下载最新的viplugin插件:viPlugin_2.12.0。

将viPlugin_2.12.0.zip文件解压到eclipse安装目录下的dropins目录下。

该插件为收费插件,在eclipse安装的根目录下新建viPlugin2.lic文件,文件内容为:_q1MHdGlxh7nCyn_FpHaVazxTdn1tajjeIABlcgJBc20
_。

重启eclipse后即可生效。

官方参考文档地址:http://www.viplugin.com/files/User_Manual_viPlugin.pdf


相关下载:viPlugin_2.12.0.zip

[TOC]

在Linux操作系统中,每个文件都有一组9个权限位来控制谁能够读写和执行该文件的内容。这组权限对于文件的意义非常容易理解。但是对于目录而言就不是那么容易理解了。要想搞明白权限机制需要了解文件系统中的inode节点和block等概念,并大致了解文件系统的内部实现原理。

文件的权限

这部分比较容易理解。比较容易搞错的为:

w位:包含对文件的添加、修改该文件内容的权限,但不包含删除文件或移动该文件的权限,因为文件的文件名信息存储在父目录的block中,而不是在该文件的inode节点中。父目录的block中包含该文件的inode节点和文件名信息,通过父目录中的inode节点找到该文件。

目录的权限

r位:表示具有读取该目录列表的权限。

w位:对该文件夹下创建新的文件或目录进行增加、删除、修改操作。

x位:这个稍微难以理解。表示用户能否进入该目录成为工作目录,即是否可以cd到该目录。通常和r位组合一块使用。

例子一

假设root用户对testing目录和testing目录下的testing文件拥有的如下权限:

1
2
3
[root@localhost tmp]# ls -ald testing/ testing/testing
drwxr--r--. 2 root root 4096 3月 1 11:44 testing/
-rw-------. 1 root root 0 3月 1 11:44 testing/testing

kuring用户拥有对该文件夹的读权限,但是没有x权限。当kuring用户访问时会提示如下内容:

1
2
3
4
5
6
7
8
9
// 拥有r的权限可以查询文件名,但是没有x权限,不能读取除文件名外的其他信息,产生了问号。
[kuring@localhost tmp]$ ll testing/
ls: 无法访问testing/testing: 权限不够
总用量 0
-????????? ? ? ? ? ? testing

// 没有x权限,不能进入该目录
[kuring@localhost tmp]$ cd testing/
bash: cd: testing/: 权限不够

例子二

在上述例子中,给kuring用户增加对目录testing的rwx权限,却只拥有testing目录下的testing文件的r权限。权限情况如下所示:

1
2
3
[kuring@localhost tmp]$ ls -ald testing testing/testing
drwxr--rwx. 2 root root 4096 3月 1 13:29 testing
-rw-r--r--. 1 root root 0 3月 1 13:29 testing/testing

kuring用户执行如下操作:

1
2
3
4
5
6
7
8
9
10
// 当对文件进行更改时由于没有对文件的w权限,操作失败
[kuring@localhost tmp]$ echo "world" >> testing/testing
bash: testing/testing: 权限不够

// 当对文件进行删除操作时却可以删除该文件,这是因为文件删除操作的权限是由该文件所在目录的w位决定的
// 文件删除操作会修改父目录中block节点中的文件名内容,而父目录的权限为rx,不可写。
[kuring@localhost tmp]$ rm testing/testing
rm:是否删除有写保护的普通文件 "testing/testing"?y
[kuring@localhost tmp]$ ls testing/
[kuring@localhost tmp]$

只有了解了原理,就可以理解在多级目录并且目录的权限不一致的情况下相应的权限问题了。


进程用户ID

要讲解set uid和set gid,就涉及到进程的用户ID概念。用户ID又可以分为两部分:

  • 实际用户ID和实际组ID:标识了究竟是哪个用户执行了该程序,跟命令行中的登录用户一致,可以通过id命令查看。

  • 有效用户ID和有效组ID:系统通过有效用户ID、有效组ID和附加组ID来决定进行对系统资源的访问权限。在Linux系统中一个用户可以属于多个组,在/etc/passwd文件中一个用户仅能标识出隶属于一个组ID,该组ID叫做默认的组ID。在/etc/group为文件中可以标识出一个用户隶属于多个组,这多个组中除去默认的组ID叫做附加组ID。

set uid

  • 该权限位仅对二进制文件有效
  • 执行者对该程序需要具有x的权限
  • 该权限仅在执行该程序过程中有效
  • 执行者将具有该程序拥有者的权限

以/usr/bin/passwd命令为例,该程序的权限为:rwsr-xr-x。普通用户可以调用该程序修改自己的密码,而密码文件/etc/shadow未设置任何权限,即只有root用户可以操作该文件。

1
2
3
4
[root@localhost tmp]# ll /usr/bin/passwd
-rwsr-xr-x. 1 root root 30768 2月 22 2012 /usr/bin/passwd
[root@localhost tmp]# ll /etc/shadow
----------. 1 root root 1248 11月 30 10:50 /etc/shadow

passwd文件的s标志表明setuid位被设置。

passwd的拥有者为root;当普通用户执行passwd命令时,普通用户具有该命令的执行权限;passwd执行该命令时会暂时获得root用户权限;/etc/shadow就可以被修改。

也许看到这里就会有疑问:那岂不是普通用户可以通过/etc/passwd命令修改其他用户的密码了。之所以不可以这么操作是因为passwd命令内部通过逻辑实现。

set gid

设置在文件上的情况:

  • 该权限位仅对二进制文件有效
  • 执行者对该程序需要具有x的权限
  • 执行者在运行程序的过程中将会获得该执行群组的权限

设置在目录上的情况:

  • 用户对目录具有r和x的权限
  • 用户在目录下的有效群组将会变成该目录的群组
  • 若用户在此目录下具有w的权限,使用者建立的群组与该目录的群组相同

粘附位(sticky bit)

该权限位仅对目录有效,如果在目录上设置了粘附位,只有该目录的属主、该文件的属主或root用户可以删除或重命名该目录文件。

/tmp文件夹的权限如下,其中的t位表示粘附位:

1
2
[kuring@localhost /]$ ll -ad tmp/
drwxrwxrwt. 25 root root 4096 3月 1 14:51 tmp/

如果在/tmp下kuring用户创建了自己的文件kuring_file,并设置权限为777,test用户并不能删除该文件

1
2
3
4
5
6
7
8
9
10
11
12
[kuring@localhost tmp]$ touch kuring_file
[kuring@localhost tmp]$ ll kuring_file
-rw-rw-r--. 1 kuring kuring 0 3月 1 15:05 kuring_file
[kuring@localhost tmp]$ chmod 777 kuring_file
[kuring@localhost tmp]$ ll kuring_file
-rwxrwxrwx. 1 kuring kuring 0 3月 1 15:05 kuring_file

[kuring@localhost tmp]$ su - test
密码:
[test@localhost ~]$ cd /tmp/
[test@localhost tmp]$ rm kuring_file
rm: 无法删除"kuring_file": 不允许的操作

表示方法

如果设置了setuid位,属主的执行权限中的x用s来代替;
如果设置了setgid位,组执行权限中的x用s来代替;
如果设置了sticky位,权限最后的那个字符被设置为t;
如果设置了setuid、setgid或sticky位中一个,又没有设置相应的执行位,这些位显示为S或T。

权限设定方式

4为setuid位,2为setgid位,1为sticky位。具体参考《鸟哥的Linux私房菜》。

参考文档

《鸟哥的Linux私房菜》
《UNIX/Linux系统管理技术手册》

在使用SSH或者telent远程登录到Linux 服务器,经常运行一些需要很长时间才能完成的任务,比如系统备份、ftp 传输等等。通常情况下我们都是为每一个这样的任务开一个远程终端窗口,因为它们执行的时间太长了。必须等待它们执行完毕,在此期间不能关掉窗口或者断开连接,否则这个任务就会被杀掉,一切半途而废了。

安装

CentOS下默认没有安装该命令,从screen的官方网站下载,下载地址:http://ftp.gnu.org/gnu/screen/。

  1. 解压后执行./configure
  2. 执行make命令。在执行make命令时会遇到错误pty.c:38:26: 错误:sys/stropts.h:没有那个文件或目录,在/usr/install/sys/目录下创建一个stropts.h的空文件即可。
  3. 执行make install,该命令并不会将screen命令复制到系统的PATH变量包含的路径下,即不能执行screen命令。
  4. 执行install -m 644 etc/etcscreenrc /etc/screenrc
  5. 执行cp screen /bin/
  6. 执行cp doc/man/man1/screen.1 /usr/share/man/man1/,即可以可使用man screen查看帮助。

实现原理

当关闭窗口或断开连接时,内核会将SIGHUP信号发送到会话期首进程,进程对SIGHUP的处理动作为终止。如果会话期首进程终止,则该信号发送到该会话期前台进程组。一个进程退出导致一个孤儿进程组中产生时,如果任意一个孤儿进程组进程处于STOP状态,发送SIGHUP和SIGCONT信号到该进程组中所有进程。因此当网络断开或终端窗口关闭后,控制进程收到SIGHUP信号退出,会导致该会话期内其他进程退出。

为解决上述问题,Linux程序在设计时可设计成守护进程的方式启动。

另外也可以通过nohup 命令 &的方式启动来解决问题。

新建screen

  • 直接输入screen命令即可使用。
  • 输入screen -S kuring,这里给screen取了一个名字,方便辨认。
  • screen 命令直接在screen中执行命令,命令结束后screen退出。

分离与恢复

在screen窗口中执行ctrl + a d命令,screen会给出_[detached]_提示,并恢复到执行screen之前的bash。
查找之前的screen执行screen -ls,会列出当前打开的screen。

1
2
3
4
There are screens on:
8576.pts-3.localhost (Attached)
8449.kuring (Detached)
2 Sockets in /tmp/uscreens/S-kuring.

这里系统中打开了两个screen,一个为Attached,另一个为Detached。

重新连接执行screen -r kuringscreen -r 8449screen -r,当系统中仅有一个处于Detached状态的screen时就可以直接执行screen -r命令。

关闭窗口

在screen的shell中执行exit命令即可关闭screen。

也可以执行ctrl + a k,会杀死当前screen中的所有运行进程。

错误

在screen中执行vi命令时会提示_E437: terminal capability “cm” required_错误,执行echo $TERM查看发现打印值为_screen_,而未执行screen时的bash打印值为_xterm_,在screen中执行export TERM=xterm即可解决该问题。

参考文档

更多高级使用方法请参考以下文档:

linux 技巧:使用 screen 管理你的远程会话
linux screen 命令详解

trim函数在其他语言中比较常见,这里用C语言实现一个,不使用C语言的库函数。该例子中不需要额外的申请空间,算法的时间复杂度为O(1)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <stdio.h>

char *trim(char * str)
{
char *buf1, *buf2;
int i;
if (str == NULL)
{
return NULL;
}

// 处理字符串前面的空格
for (buf1=str; *buf1 && *buf1==' '; buf1++);

// 将去掉前面空格的字符串向前复制
for (buf2=str, i=0; *buf1;)
{
*buf2++ = *buf1++;
i++;
}
*buf2 = '\0';

// 处理字符串后面的空格
while (*--buf2 == ' ')
{
*buf2 = '\0';
}
return str;
}

int main(int argc, char *argv[])
{
printf("trim(\"%s\") ", argv[1]);
printf("returned \"%s\"\n", trim(argv[1]));
return 0;
}

本文是VMWare下的CentOS操作系统将yum源更改为光盘的实例,光盘的iso文件存放在宿主机器上,通过VMWare的共享文件夹功能与CentOS系统共享文件。CentOS中共享文件夹的存放路径为/mnt/hgfs中。CentOS的光盘为两张,分别为CentOS-6.5-x86_64-bin-DVD1.iso、CentOS-6.5-x86_64-bin-DVD2.iso。注意LiveCD版的CentOS系统盘是不可以作为yum源的。

挂载光盘

  1. mkdir -p /media/cdrom;mkdir -p /media/CentOS,创建挂载两个挂载目录,分别挂载DVD1和DVD2。
  2. 执行mount /mnt/hgfs/iso/CentOS-6.5-x86_64-bin-DVD1.iso /media/cdrom/ -o loop;mount /mnt/hgfs/iso/CentOS-6.5-x86_64-bin-DVD2.iso /media/CentOS/ -o loop;,将iso挂载到创建的目录下。
  3. 执行df -h命令即可看到挂载的文件系统,输出如下:
    1
    2
    /mnt/hgfs/iso/CentOS-6.5-x86_64-bin-DVD1.iso  4.2G  4.2G     0 100% /media/cdrom
    /mnt/hgfs/iso/CentOS-6.5-x86_64-bin-DVD2.iso 1.2G 1.2G 0 100% /media/CentOS

设置本地yum源

在/etc/yum.repos.d目录下CentOS-Base.repo记录着yum通过网络更新的源,CentOS-Media.repo记录着通过本地文件更新的源。其中CentOS-Media.repo文件的内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# CentOS-Media.repo
#
# This repo can be used with mounted DVD media, verify the mount point for
# CentOS-6. You can use this repo and yum to install items directly off the
# DVD ISO that we release.
#
# To use this repo, put in your DVD and use it with the other repos too:
# yum --enablerepo=c6-media [command]
#
# or for ONLY the media repo, do this:
#
# yum --disablerepo=\* --enablerepo=c6-media [command]

[c6-media]
name=CentOS-$releasever - Media
baseurl=file:///media/CentOS/
file:///media/cdrom/
file:///media/cdrecorder/
gpgcheck=1
enabled=0
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-6

其中已经包含了/media/cdrom路径和/media/CentOS路径,至此配置已经完毕。

安装软件需要通过命令yum --disablerepo=\* --enablerepo=c6-media [command],执行yum [command]命令时还是联网执行。

设置开启启动自动挂载iso文件

在/etc/fstab文件中的末尾增加如下内容:

1
2
/mnt/hgfs/iso/CentOS-6.5-x86_64-bin-DVD1.iso /media/cdrom/ iso9660 loop 0 0
/mnt/hgfs/iso/CentOS-6.5-x86_64-bin-DVD2.iso /media/CentOS/ iso9660 loop 0 0

X Window的实现机制还是比较难以理解的,尤其是跟软件开发中的客户端-服务器模式不太一样。涉及到概念也比较多,甚至很对教程对概念的理解不一。最近深入学习了下X Window的原理,在此做一下整理。先上一个摘自维基百科的图:
X Window架构

常用快捷键
ctrl+alt+fn:切换到相应的虚拟控制台,n为1-12。默认情况下,linux操作系统会在1-6上运行6个虚拟控制台。
ctrl+alt+退格键:关闭X window系统。
在vmware环境下,ctrl+alt快捷键跟vmware冲突,需要先按住ctrl+alt,然后按一下空格键并松开,再按下相应的fn键才能使用。

X Server
负责硬件管理、屏幕绘制、字体,并接收输入设备(如键盘、鼠标等)的动作,并且告知X Client。
Linux下的X Server软件为Xorg,通过X(Xorg的链接文件)命令即可执行。
输入X命令后,会在第7个控制台启动X Server,将会出现一个什么都没有的漆黑界面,这是由于没有任何X client程序输入的原因。
可以在Linux下启动多个X Server软件,从0开始编号。如果再执行X:2命令会启动第二个X Server,此时X Server会在第8个控制台运行。如果第一次执行的是X:2命令则X Server会在第7个控制台运行。
在Windows操作系统下的Xming、Xmanager等可以远程连接Linux界面的软件其实就是X Server。

X Client
即X应用程序,运行在X Window下的窗口程序都属于X client。比如firefox就是一个X Client。接收来自X Server的处理动作,将动作处理成为绘图数据,并将绘图数据传回给X Server。X Client与X Server之间通过X Window System Core Protocol协议进行通讯。
xclock是一个简易的X Client的时钟程序,在:1上启动X Server后,执行xclock –display :1&命令将xclock输出到X Server后的画面如下:
xclock
该程序可以在X Server上执行,但是画面非常简陋,甚至没有窗口的菜单栏和最大化等按钮。

Window Manager
一种特殊的X Client,提供了窗口的样式。常用的Window Manager包括GNOME默认的metacity、twm等。
将metacity输出到:1上的X Server的命令为metacity –display=:1 &,效果如下:
Image Title
可以看到窗口多出了最小化、最大化、关闭按钮,并且窗口可以移动和缩放等操作。

Display Manager
提供用户登录画面、帮助X Server建立Session。
gnome采用的Display Manager为gdm,KDE采用kdm,还有tdm、xdm等。

Desktop Manager
X Server、X Client、Window Manager的一个集合。常用的Desktop Manager包括:KDE、GNOME等。

startx启动流程
在命令行下执行startx命令后,系统直接进入了桌面环境,并未出现登录界面。进程树如下:
Image Title

  1. startx会调用xinit命令,xinit命令的主要是启动一个X Server软件。
  2. 接着xinit命令会调用gnome-session启动gnome的环境所需要的软件。

init 5启动流程
在命令行下执行init 5,首先出现的画面为登录信息。进程树如下:
Image Title

  1. 执行/etc/rc.d/rc5.d中的daemon。
  2. 执行/etc/X11/prefdm文件,会选择启动gdm、kdm、xdm、tdm。
  3. 这里以gdm为例,gdm是一个shell脚本,会启动gdm-binary命令。

实战
Windows主机连接Linux的教程参见我的另外一篇文章《Redhat安装完成之后的设置》中的相关部分。
两台Linux机器之间通过XWindow实现连接的用法比较少见,通常情况下可以通过vnc代替。
Linux主机连接Windows的工具为rdesktop。

参考文章
《鸟哥的Linux私房菜》
《Linux操作系统之奥秘》
视频:RH033-ULE112-16-linux下X图形显示体系
视频:Xwindow详解

本文对Linux常用的网络命令进行整理和总结。

连通性测试

ping命令

最常用的网络诊断命令。

1
2
3
4
5
6
7
8
[kuring@localhost ~]$ ping www.baidu.com
PING www.a.shifen.com (61.135.169.125) 56(84) bytes of data.
64 bytes from 61.135.169.125: icmp_seq=1 ttl=128 time=25.5 ms
64 bytes from 61.135.169.125: icmp_seq=2 ttl=128 time=20.3 ms
64 bytes from 61.135.169.125: icmp_seq=3 ttl=128 time=25.0 ms
64 bytes from 61.135.169.125: icmp_seq=4 ttl=128 time=21.7 ms
64 bytes from 61.135.169.125: icmp_seq=5 ttl=128 time=23.4 ms
64 bytes from 61.135.169.125: icmp_seq=6 ttl=128 time=21.9 ms

通过上述输出可以看出,ping命令可得到DNS对应的IP信息、ping的数据包大小、网络延迟信息。

另外,可以通过-s参数指定ping的数据包大小。例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
kuring@ubuntu:~$ ping www.baidu.com -s 1024
PING www.a.shifen.com (61.135.169.125) 1024(1052) bytes of data.
1032 bytes from 61.135.169.125: icmp_req=1 ttl=55 time=22.6 ms
1032 bytes from 61.135.169.125: icmp_req=2 ttl=55 time=22.9 ms
1032 bytes from 61.135.169.125: icmp_req=3 ttl=55 time=53.0 ms
1032 bytes from 61.135.169.125: icmp_req=4 ttl=55 time=28.0 ms
1032 bytes from 61.135.169.125: icmp_req=5 ttl=55 time=54.7 ms
1032 bytes from 61.135.169.125: icmp_req=6 ttl=55 time=93.1 ms
1032 bytes from 61.135.169.125: icmp_req=7 ttl=55 time=26.9 ms
1032 bytes from 61.135.169.125: icmp_req=8 ttl=55 time=25.2 ms
1032 bytes from 61.135.169.125: icmp_req=9 ttl=55 time=25.4 ms
^C1032 bytes from 61.135.169.125: icmp_req=10 ttl=55 time=21.2 ms

--- www.a.shifen.com ping statistics ---
10 packets transmitted, 10 received, 0% packet loss, time 45436ms
rtt min/avg/max/mdev = 21.225/37.350/93.149/21.966 ms

会发现ping命令的响应时间变长了,这正是由于ping发送数据包变大了。

traceroute

可以显示路由信息。

mtr

traceroute命令的升级版,可以动态刷新路由信息,可以显示路由上每个节点的丢包率和时间等信息,信息比较全面和直观。

arp相关

arping

可以通过该命令查看IP地址对应的mac地址。arping IP地址会立即发送一个arp广播,可以根据收到的arp回应的多少看局域网内是否中arp病毒、IP地址冲突等情况。

arp

跟arp协议相关,可以设置arp表、读取arp表等。

端口相关

telnet

可以利用该命令来测试某个端口是否打开。例如执行telnet localhost 881其中881为本机的未打开端口,会产生如下输出:

1
2
Trying 127.0.0.1...
telnet: connect to address 127.0.0.1: Connection refused

执行telnet localhost 22,其中22端口为本机的ssh服务端口且已经打开,会产生如下输出:

1
2
3
4
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
SSH-2.0-OpenSSH_5.3

则表示本机的22端口已经打开。

netstat

查看本机网络端口命令,常用netstat -aunp

#DNS相关

host

1
2
3
4
kuring@ubuntu:~$ host www.google.com.hk
www.google.com.hk is an alias for www-wide.l.google.com.
www-wide.l.google.com has address 74.125.128.199
www-wide.l.google.com has IPv6 address 2404:6800:4005:c00::c7

nslookup

1
2
3
4
5
6
7
8
kuring@ubuntu:~$ nslookup www.google.com.hk
Server: 127.0.0.1
Address: 127.0.0.1#53

Non-authoritative answer:
www.google.com.hk canonical name = www-wide.l.google.com.
Name: www-wide.l.google.com
Address: 74.125.128.199

dig

可以代替nslookup的命令,显示的域名信息更为详细。

其他

ab

Linux下的压力测试工具,可以模拟多个客户端发送多个请求。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
kuring@ubuntu:~$ ab -c 100 -n 100 http://kuring.me/
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking kuring.me (be patient).....done


Server Software: Tengine/2.0.0
Server Hostname: kuring.me
Server Port: 80

Document Path: /
Document Length: 707 bytes

Concurrency Level: 100
Time taken for tests: 1.547 seconds
Complete requests: 100
Failed requests: 10
(Connect: 0, Receive: 0, Length: 10, Exceptions: 0)
Write errors: 0
Non-2xx responses: 90
Total transferred: 145330 bytes
HTML transferred: 126570 bytes
Requests per second: 64.64 [#/sec] (mean)
Time per request: 1546.990 [ms] (mean)
Time per request: 15.470 [ms] (mean, across all concurrent requests)
Transfer rate: 91.74 [Kbytes/sec] received

Connection Times (ms)
min mean[+/-sd] median max
Connect: 173 223 43.8 200 289
Processing: 167 340 301.5 236 1368
Waiting: 166 339 300.5 235 1364
Total: 345 563 295.4 438 1546

Percentage of the requests served within a certain time (ms)
50% 438
66% 555
75% 562
80% 597
90% 1108
95% 1474
98% 1484
99% 1546
100% 1546 (longest request)

参考

0%