原文:http://blog.csdn.net/ye_wei_yang/article/details/52777499html
1、Linux的磁盘分区及目录linux
Linux的配置是经过修改配置文件来完成。程序员
1.一、Linux磁盘分区shell
Linux能够将磁盘分为多个分区,每一个分区能够被当作一个独立的磁盘使用,磁盘类型:主分区、扩展分区、逻辑分区。编程
主分区标记为活动,用于操做系统的引导,一块磁盘最多划分4个主分区,主分区存放操做系统的文件或用户数据。ubuntu
扩展分区:主分区小于4个时才能够划分扩展分区,一块磁盘最多有一个扩展分区,扩展分区不能保存任何数据,必须在扩展分区中进一步划分逻辑分区,用户数据只能保存在逻辑分区中。vim
逻辑分区:扩展分区中能够创建多个逻辑分区。windows
Linux中大多数硬件都是以文件的方式进行管理,这些硬件设备被映射到"/dev"目录下对应的文件中,在‘/dev’目录下每一个磁盘分区映射为一个文件,这些文件采用字母加数据的形式,如:数组
/dev/xxyN浏览器
其中的xx表示区名所在磁盘的设备类型,通常hd表明IDE接口的磁盘,sd表明SCSI或SATA便可的磁盘(光盘驱动器及U盘),fd表明软盘驱动器,tty是一种字符型的终端设备ttySn是串口设备。“y”表示分区所在的磁盘是当前接口的第几个设备好比第一个SCSI硬盘就是“/dev/sda”,第二个SCSI硬盘就是“/dev/sdb”。“N”表示分区的序号,前四个分区(主分区或扩展分区)使用1-4表示,逻辑分区从5开始。
分区完成后,用户并不能直接使用这些分区,须要格式化后再经过 mount命令挂载后才能使用,如使用mount命令将“/dev/sdb2”挂载到“/mnt/disk”目录,全部保存到/mnt/disk目录下的数据就会被保存到/dev/sdb2分区中。
1.二、Linux文件系统及目录结构
文件系统是一种存储和组织计算机文件及数据的方法,文件系统一般使用硬盘和光盘的存储设备,并维护设备中的物理位置。
Linux操做系统默认操做FAT、FAT32两种文件系统,默认状况下不支持NTFS系统,推荐使用ext3(第三版的扩展文件系统)文件系统。ext3是一种日志文件系统,在对系统数据进行写操做前,会把写操做内容写入一个日志文件中,一旦操做被意外停止,系统可以在从新启动时根据日志完成该写操做。
Linux文件系统中,文件是存储信息的基本结构。文件、目录、硬件设备都以文件的形式表示,文件名能够由字符、数据、原点、下划线组成,长度不超过256个字符。Linux中经过圆点区分文件名和扩展名帮助用户区分文件类型,用户能够根据本身须要随意假如本身的扩展名。Linux中有4种文件类型:普通文件,如文本文件、图片文件、视频文件、shell脚本文件;目录文件:特殊的文件;连接文件;特殊文件;
文件系统采用树形的结构。
Linux中每一个用户有个家目录,若是是管理员(root用户)家目录是/root,如果普通用户家目录是/home。路径,从一个目录到另外一个目录或文件的道路被称为路径,“.”表示当前目录,“..”当前目录的父目录,“~”当前用户的家目录,“-”上一个目录。
2、经常使用命令
poweroff:关闭系统 reboot:重启计算机 clear:清除终端显示 pwd :显示当前目录 cd:改变当前目录 . :表示当前目录 .. : 表示当前目录的父目录 ~“”表示home目录
- 上一个工做目录
mv :移动命令 cp:复制命令 rm:删除命令 mount:挂载命令 chamod:改变权限命令
cat:打印命令 mkdir:新建文件夹 lsmod:查询设备
netstate -nl :查看网络状态 netstate -nlu :查看UDP状态
ifconfig 查看网络配置 ifconfig -a:全部的网卡 ifconfig eth0 up/down 打开或关闭eth0设备 ifconfig 能够用来配置IP和网络掩码。 ping:查看网络是否通 date:查询时间 date -s :修改系统时间 cal:日历
man 命令:查看命令的使用方法。 kill 进程号:结束一个进程
2.一、vim命令
命令模式,启动后默认处于该模式,其余模式用ESC键或者Ctrl+C切换到命令模式。
插入模式,和txt文档编辑同样编辑,在命令模式下用i、o、a命令进入该模式。
可视模式,该模式下可用方向键进行内容选择,而后进行复制、粘贴和其余操做,在命令模式下使用v进入该 模式。
块操做模式,该模式下可用方向键进行内容选择,选择时可模拟鼠标选择的方式。在命令模式下使用ctrl+v进入该模式
修改模式,该模式下,相似于其余软件用insert键来完成切换。命令模式下用R进入该模式。
扩展命令模式,该模式下能够执行一些扩展命令。命令模式下使用‘:’进入该模式。
vim几种操做选择:“o” 能够只读方式打开该文件,“e”可正常编辑,使用该方式注意肯定其余用户没有正在编 辑这个文件,“r”从临时交换文件中回复,“q”退出编辑该文件,“a”放弃并同时撤销后续命令的执行,“d”删除临时交换文件。
文件编辑完成,但愿关闭须要首先切换到命令模式,击中退出方式::q 直接退出,:q!强行退出,若是文件内容发生改变则不保存,:wq保存并退出,:wq!强行保存并退出,通常用于文件是只读的状况下,可是文件的拥有者是当前用户。
2.二、Vim经常使用的操做键
命令模式经常使用的操做键:
G:移动到文件的最后一行
nG:n为数字,移动到文件的第n行。
/word: 向下查找关键字word
?word: 向上查找关键字word
n:重复前一个查找
N:反复重复前一个查找
:n,$s/a/b: 替换第n行开始到最后一行中每一行的第一个a为b。
:n$s/a/b/g: 替换第h开始到最后一行每一行全部的a为b,n位数字,若n为.表示从当前行开始到最后一行
d$: 删除光标所在位置到该行最后一个字符。
dd: 剪切当前行。
yy: 复制所选内容
nyy: 复制从光标开始n行内容
p: 将已经复制的内容粘贴到光标下一行。
P: 将已经复制的内容粘贴奥光标上一行。
u: 复原上一个操做。
ctrl+R: 重复前一个操做。
o: 当前下插入空行,并进入插入模式。
O: 当前下插入空行,并进入插入模式。
. : 重复前一个动做。
i : 进入插入模式,从当前光标所在位置插入。
I : 插入模式,从当前行第一个非空格处插入。
r : 插入模式,替换光标所在字符。
R: 进入修改模式。
ESC键:返回命令模式。
(2) 扩展命令模式经常使用操做键
:w ---- 保存。
:w! ---- 文件为只读时强制保存,不过可否保存还要看文件的权限。
:q ---- 离开vim。
:q! ----- 强制退出。
:wq ------- 保存后离开。
:x ------ 保存后离开。
:w[文件名] ----- 另存为新文件。
v ---------- 进入可视模式。
ctrl+V ------ 进入块操做模式。
:r[文件名] ----- 将文件名的文件读到光标后面。
n1,n2 w[文件名] ----- 将n1到n2另存为新文件
:new ----- 新增水平窗口
:new filename --- 新增水平窗口,并在新增的窗口加载filename文件。
:v new ----- 新增垂直窗口。
:v filename ----- 新增垂直窗口,并在新增窗口加载filename文件。
ctrl+W+方向键 ---- 切换窗口。
:only ---- 紧保留目前的窗口。
:set nu ----- 显示行号
:set nonu ---- 不显示行号
:set readonly ----- 文件只读,除非使用!可写。
:set ic ---- 查找是忽略大小写。
:set noic ---- 查找时不忽略大小写。
3、桌面环境
Linux的桌面图形界面有不少种,GNOME KDE Fluxbox Xfce FVWM sawflish WindowMaker等,最经常使用的是GNOME和KDE两种。
3.一、远程管理
Telnet协议是Internet远程登陆服务的标准协议,提供了在本地计算机上完成远程主机工做的能力,用户能够在Telnet程序中输入命令,这些命令会在远程服务器上运行。传统的Telnet安全性差,许多服务器会将Telnet服务关闭,使用更安全的SSH。
ubuntu 开启Telnet服务步骤, http://www.linuxdiyf.com/linux/17355.html
SSH是Secure Shell 的缩写,为创建在应用层和传输层上的安全协议,SSh对所传数据进行加密保证了数据的安全并且数据是通过压缩的提升了传输速度。SSH能够代替Telnet,又能够为TFP、POP提供一个安全通道。
Linux及windows客户端经过SSH连接到服务器的方法:
(1) Linux客户端
Linux客户访问SSH服务器经过如下几个命令完成:
① ssh [-CflRv] [用户名@] SSH服务器 [命令] ,
SSH服务器指定要连接的服务器,能够使用FQDN或IP地址。
用户名@:指定连接SSH服务器的用户名,不指定用户时默认以root用户连接。
命令:使用ssh命令能够连接到服务器,有时须要在SSH服务器上执行一个命令时,能够直接经过此 参数指定须要执行的命令。
-C:启用压缩功能
-f: 在询问密码以后且在执行[命令]以前,将ssh转到后台运行。
-L:将本地系统中的某个端口转发到远程系统。
-R: 将远程系统 的某个端口转发到本地端口
-v: 显示与链接和传送有关的调试信息。
例如: ssh 192.168.159.11 经过ssh链接到远程计算机,默认使用root用户。若是是第一次链接到远 程计算机,本地主机的用户须要生成链接远程主机的RSA公钥,在此出现的警告输入yes。退出远程 链接服务器,输入exit。
② SCP命令能够使用SSH的方式在远程主机和本地主机复制文件或目录,语法以下,
scp [-Cpqrv] [[用户名@]复制源主机:]复制源文件[[用户名@]复制目标主机:][复制目标文件]
若是是windows客户端,能够用putty。
(2) RDP
在Windows中可经过“远程桌面”功能链接到远程的计算机进行管理。
4、Linux命令基础
4.一、Linux命令分类
Linux操做系统中,命令分为两种:Shell内部命令、Shell外部命令。
Shell内部命令:shell内部命令是一些较为简单的又经常使用的命令,如cd、mkdir、rm等,这些命令在shell启动时载入内存。
Shell外部命令:Linux中大多数命令属于外部命令,每个shell外部命令都一个独立的可执行程序,也就是shell的外部命令是一些实用工具程序,管理员能够独立的在shell环境下安装或卸载这些shell外部命令。
Linux的内部命令能够在任何目录任什么时候间执行,而外部命令在执行时,Linux必须找到对应的可执行程序。Shell中一个名为PATH的环境变量,该变量包括一些路径用于shell自动搜索。
cat /etc/shells 来查看系统中的shell种类。
Shell中的引号分为三种:单引号,双引号,反引号
由单引号引发来的符号都做为普通字符出现。特殊字符用单引号引发来后,失去原来的意义,变为普通字符解释。
双引号的做用与单引号相似,区别在于没那么严格,单引号忽略全部的特殊字符,双引号中的3中特殊字符不被忽略 $ \ '。
反引号· 位于键盘的左上角,被反引号引发来的被shell解释为 命令行
用#作注释。
4.二、Linux命令格式
Shell解释器在用户和内核之间至关于一个翻译的角色,负责解释用户输入的命令。shell是操做系统和用户进行交互的界面。命令的基本格式:
命令 [选项] [参数]
命令是须要执行的操做,选项是对命令的要求,参数用于描述命令的做用对象。好比 ls -l /root ,命令是ls,选项-l表示要以长格式显示文件信息,/root 是 ls的命令参数,表示ls命令做用的对象是 /root目录。
5、Linux的目录及文件管理
5.一、Linux的主要目录
/ :根目录,一台计算机只有一个根目录,全部内容都是从跟目录开始。如/etc ,先从根目录开始在进入etc目录
/root:系统管理员的家目录。
/bin:存放了标准的Linux工具,如ls、cp、rm等。该目录已经包含在PATH中,使用该目录程序无需使用路径
/boot:用于加载程序的文件。
/proc:操做系统运行时,进程信息及内核信息,若是CPU、硬盘分区、内存信息等存放在该目录。
/etc:存放系统的配置方面的文件,如在系统安装vsftpd这个软件,你想要修改vstpd配置文件的时候,vstpd的配置文件就在/etc/vstpd目录下。
/etc/init.d 存放系统或以system V模式启动的服务脚本。
/etc/xinetd.d: 若是服务是经过xinetd模式运行的,服务的脚本要放在这个目录下。
/etc/rc.d : 存放BSD方式启动脚本,如定义网卡开启脚本等。
/etc/X11:存放X-Windows相关的配置文件
/dev :主要存放与设备(包括外设)有关的文件。
/home :存放每一个用户的家目录。每一个用户的设置文件,桌面文件夹、用户数据都放在这里。
/tmp :临时目录。
/bin、/usr/bin:大部分系统命令都是二进制文件形式保存。通常用户使用的命令都在这两个目录,系统核心命令工具,如cd、ls、cp、等都在/bin目录。如Web浏览器为于/usr/bin目录,能够与其余用户共享使用。
/sbin、/usr/sbin :存放root用户的命令文件。
/usr/local :用于存放手动安装的软件。
/usr/share:存放系统共用的文件。
/usr/src:存放内核源码的目录。
/var :存放一些常常变化的文件。
/var/log:存放系统的日志。
/opt:存放那些可选的程序。
/lib:系统的库文件
/lost+found:在文件系统中,系统意外崩溃或意外关机时,产生的一些文件碎片放在该目录。
/mnt : 存放挂在存储设备的挂载目录。
/meia:有些发行版使用这个目录来挂载那些USB接口的移动硬盘,CD/DVD驱动器等。
5.2目录结构及操做命令
Linux系统中,以.开头的文件名表示该文件是隐藏文件, ls命令用于显示指定目录的内容,语法:
ls [-anruhtFS1R] --time=<atime|ctime> --color<=使用时机> [目录...]
[目录...]:指定要显示内容的目录或目录缩写,若是须要显示多个目录,可在目录名之间使用空格
-a:显示包括影藏文件在内的全部文件及目录。
-n:使用UID和GID代替用户名显示文件或目录全部者和拥有者。
-r:反向排序。
-u:以最后存取时间排序,显示文件和目录。
-h:使用k、M、G为单位,提升信息可读性。
-t:根据文件和目录最后修改时间的顺序显示文件和目录。
mkdir 建立目录,语法以下
mkdir [-p] [-m<目录属性>] 目录名称...
目录名称:须要建立的目录,若需创建多个目录,可在目录名之间使用空格分隔。
-p:若是要创建的目录父目录没建立,则一块儿创建父级目录。
-m:创建目录时,同时设置目录权限,权限设置方法与chmod命令相同。
5.三、文件操做命令
创建目录是为了有效分类管理文件。
touch:改变文件或目录时间
file:识别文件类型。 Linux系统文件的扩展名只是为了方便使用者识别文件类型,对系统自己没有任何意义。file命令能够识别文件类型,语法以下
file [-bcLz] {-f<文件名>}文件|目录
cp:复制文件或目录。将目录或文件复制到另外一个目录,语法以下:
cp [-abdfilprsuv] [-S<备份字符串>] 源文件或目录 目标文件或目录
rm:删除文件或目录,语法以下:
rm [-filrv] 文件或目录
mv:移动或改名现有的文件或目录
mv [-fiub] [-S<备份字符串>] 源目录或文件 目标目录或文件
ln:连接文件或目录,语法以下:
ln [-bdfis] [-S<备份字符串>] 源文件或目录 [连接文件]
locate:查找文件或目录,语法以下
locate 查找内容
该命令只会在保存文件和目录名称的数据苦衷查找。查找内容使用*表示任意字符,?表示任何一个字符。例如tony*zhang ,locate命令会查找以tony开始以zhang结尾的文件或目录。
which:查找文件,语法以下:
which [文件]
该命令只会在PATH环境变量中定义的 路径及命令别名中查找。
whereis:查找文件,语法以下:
whereis [-bu] [-B<目录>] [-M<目录>] [-S<目录>] [文件...]
find :查找文件或目录
gzip:压缩文件,语法以下:
gzip [-cdf1Nnqtvr] [-压缩比] [--bast|--fast] [-S<压缩字尾字符串>] 要压缩的文件
bzip2:压缩文件,语法以下:
bzip2 [-cdfktvz] [-压缩比] 要压缩的文件
tar:压缩备份,能够将多个文件合并为一个文件,打包后文件的扩展名为.tar,默认状况下不压缩tar文件,能够经过选项在打包同时进行压缩。
zip/uzip:ZIP文件压缩与解压。
不一样文件的压缩和解压缩:
.zip
解压:unzip filename.zip
压缩:zip filename.zip dirname
.rar
解压:rar -x filename,rar
压缩:rar -a filename.rar dirname
.tar.gz或tgz
解压:tar -zxvf filename.tar.gz
压缩:tar -zcvf
5.四、文本查看命令
cat:显示文件内容,语法以下
cat [-bEsT] [文件..]
head:显示文件内容的最前部分。如法以下:
head [-qv] [-c<显示数目>] [-[n]<显示行数>] [文件...]
tail:显示文件内容的末尾部分
tail [-fqv] [-c<显示数目>] [-[n]<显示行数>][文件..]
more :逐页显示文件内容
grep 查找并显示符合条件的内容,语法以下:
grep [-aciInqvwxE][-显示行数][-e<范本样式>][-f<范本样式>][-d<进行操做>][范本样式][文件或目录]
6、用户及组管理方式
用户组有两种:初始组、额外组。每一个用户必须属于一个初始组,能够同时加入多个额外组。Linux将每一个用户看作一个32位的整数,这个整数就是UID。Linux内部运做大部分都是使用UID,给人看时才会把UID转换为用户名。有三种用户类型:通常用户、超级用户(root)、系统用户。
每一个用户对应一个UID,每一个组对应一个UID,创建用户时默认创建一个与用户名相同名称的组,组的GID和用户UID相同。
Linux中全部信息都是经过配置文件的方式保存,用户及组也是。
7、软件的安装及管理
7.一、常见软件安装方式
绿色软件:无需安装直接能够使用。
提供安装程序的软件包:在软件包内提供了install.sh、setup.sh等安装程序或以.bin格式单个执行文件提供 deb方式:deb是Debian软件格式包,文件扩展名.deb,经gzip和tar打包而成,处理这些包的经典程序是dpkg,经过apt来运行。
RPM格式:RPM是在Linux洗普遍使用的软件管理器,RPM仅适用于安装用RPM来打包的软件。
源码方式:使用源码本身经过本身编译生成二进制文件的软件安装方式。
8、Shell脚本
bash Shell 支持在交互模式中一次提交多个命令执行,有三种方法:使用分号隔开、&& 条件隔开,只有前一个命令成功执行时才执行下一个命令、||条件隔开,只有在上一个命令执行失败后才执行下一个命令。
8.一、标准输出重定向
(1) 使用>将输出写入文件,若是指定文件已存在将会删除文件中原来的内容。如:ls /boot > boot.txt
(2) 使用>> 将输出追加到文件,若是指定的文件已存在将会把输出附加到文件中。
8.二、标准错误重定向
(1) 使用2> 将输出写入文件,若是指定的文件已经存在将会删除文件中原来的内容。
(2) 使用2> 将输出追加到文件
8.三、Shell脚本
脚本是为了缩短传统的“预处理-编译-汇编-连接-运行”过程而建立的计算机编程语言。脚本一般是解释运行而非编译。Shell脚本是按行解释的,每一个Shell脚本对系统来讲就是一个文本文件,在有相应权限下能够使用文本编辑器创建修改Shell脚本文件。
虽然在Linux中扩展名并无实际做用,可是为了阅读方便,脚本文件通常用sh做为扩展名。
一行中“#”以后的内容表示是注释,注释在执行过程当中被忽略。
Shell脚本文件的第一行应该指定向哪一个解释器发送指令,“#!/bin/sh”
在执行已编好的脚本时能够使用两种方式:对于有执行权限的脚本文件能够使用“./<文件名>”的方式执行,对于没有执行权限的脚本能够使用“sh<文件名>”的方式执行。
Linux系统中每一个进程都是有寿命的,全部进程都是应另个进程的请求而启动,发出请求的进程成为父进程,新启动的进程成为子进程。子进程完成自身任务退出,子进程退出后会返回一个信息给父进程,叫作返回值或退出状态,返回值是一个0~244之间的整数,进程返回0表示执行成功,任何非0都表示某种形式的失败。shell 中把上一个命令的返回值保存在一个名为“$?”的特殊变量中。能够使用“echo $?”显示上一个命令是否执行成功。
8.3.一、变量
变量就是会变化的量,Shell容许用户设置和引用shell变量,shell 变量能够用在命令和脚本中,也能够被其余程序做为配置选项而引用。Shell变量有两种类型:环境变量和局部变量。环境变量由子shell继承,局部变量只存在于建立的shell中。每一个变量都有一个名称,变量的名称能够是字母字符及下划线组成不能以数字开头。Shell在使用变量钱不须要专门的语句进行定义也不对变量区分数据类型,本质上全部的shell变量都是字符串,shell也运行比较和算术操做。
(1) 局部变量
局部变量的创建和赋值直接使用“变量名=变量值”的 方式。例如变量名strA,值为ctu
strA=ctu
变量赋值能够使用双引号单不是必须的: strA=“ctu”
变量定义以后,用户在不注销的状况下任什么时候间均可以使用已定义的变量,在使用时必须在变量名前加一个$.例如显示局部变量:echo $strA.
(2)、环境变量
Linux中容许全体进程使用“变量名=变量值”的方式定义被称为环境变量的变量。环境变量是保存在内核进程中的一部分,不管什么时候开启一个进程,子进程都会继承环境变量。用户也能够建立环境变量,环境变量的建立分两步,首先定义一个局部变量,而后使用“export”命令将局部变量提高为环境变量。
set命令显示已经定义的变量
env命令显示已定义的环境变量
“unset<变量名>”清除变量 unset strA
8.四、向脚本传递参数
脚本中能够使用“$1”接收传递给脚本的第一个参数,“$2”接收第二个参数,能够使用“$*”接收全部的参数,使用“$0”得到当前脚本的名称、使用“$#”获取传递给脚本的参数个数,使用“$$”得到当前脚本的PID。
8.五、流程控制
程序语言通常都是从上向下执行代码,shell经过判断和循环改变脚本的顺序执行。
(1)、判断结构
if、then、else语句提供测试条件,语法以下:
if<条件>; then
#条件为真时执行的内容
fi
if<条件>;then
#条件为真时执行的内容。
else
#条件为假时执行的内容。
fi
if<条件1>;then
#条件为真时执行的条件
elif<条件2>;then
#条件2为真时执行的内容。
else
#前两个条件都为假时执行的内容。
fi。
if语句都必须以fi终止,elif、else是可选的。
(2) case判断结构
case 值 in
模式1)
# 符合模式1时执行的内容
;;
模式 2)
#符合模式2时执行的内容
; ;
esac
其中;;至关于C语言中的break。若是无匹配模式使用星号*匹配该值,再接收其余输入,至关于default。*表示任意字符,?表示任意单字符。
循环结构
bash shell 支持三总类型的循环:for循环一次处理循环体内容直到循环耗尽,until循环直到条件为真前一次执行循环体内的内容,while循环直到条件为假前一次执行循环体内的内容。
while[条件]
do
循环体
done
until [条件]
do
循环体
done
for((初始值;限制值;步长))
do
循环体
done。
有两种方法退出或路过循环:(1)break 用于跳出循环,break直接跳出循环,执行循环后边的,若是是循环嵌套使用break默认是跳出当前循环,也能够指定跳出循环的个数break 2 跳出两套循环。(2)continue 跳出本次循环,执行新一轮的循环。
8.六、函数
function 函数名
{
#函数内容
}
函数能够放在同一个文件中做为一段代码,也能够放在只包含函数的单独文件中,使用函数时像执行脚本同样传入参数。在函数体内容也能够用$1 $2的方式传入参数。
9、Linux引导及进程管理
10.一、加载引导程序
BIOS自检最后一步中BIOS把磁盘的第一个数据块(MBR,Master Boot Record)装入内存,并把执行传递这个区域,分为两个阶段执行
(1) 第一阶段,引导程序很小,惟一任务就是定位、装载并把控制权传递给第二阶段的引导程序,这段程序在MBR中因此在文件系统中找不到。
(2)第二阶段,引导程序自己,可以读取有关默认设备的配置信息。第二阶段应道程序一般是文件系统中可识别的二进制文件,完成如下任务:编写合适内核命令行,用于引用正确的根分区;装载合适的初始虚拟磁盘;装载合适的Linux内核并将控制权交给内核。
Ubuntu使用的引导程序是GRUB,GRUB是GNU项目的操做系统引导程序,在/boot/guab目录下,主要配置文件是/boot/grub/grub.conf文件。
GRUB加载内核参数并把控制权交给内核后,Linux内核将完成如下操做:(1) 运行init进程,Linux内核启动的第一个进程就是/sbin/init,这个命令是系统启动时由内核执行的,所以其进程ID(PID)永远是1,只要系统运行init进程就会一直运行,init进程也是系统中最后一个被终止的进程,该进程不接收SIGKILL 信号。init进程功能是启动、中止、监控其余进程。init启动时会读取配置文件/etc/inittab. inittab文件开机是执行,若是改变过了该文件须要重启。用runlevel查看运行级别。
启动时登陆shell首先读取脚本文件/etc/profile,该脚本初始化各类环境变量如PATH、HOSTNAME。
10.二、Linux内核模块
内核是操做系统的核心组成部分,主要两个功能:一是充当资源管理器,向进程透明分配内存、CPU访问等资源;二是充当解释器,在进程和硬件之间专递信息。
内核通常使用模块和硬件设备交流,每一个模块代码都单独放在一个目标文件中,能够根据须要加载和删除内核模块,内核模块位于/lib/modules/$(uname -r) 目录中,用ls /lib/modules/$(uname -r)查看和管理模块。
lsmod 命令显示当前加载到内核的模块。
modprobe 装载内核模块
rmmod 从内存中删除内核模块
10.三、/proc 目录
proc文件系统是一个伪文件系统,只存在内存中,不占用硬盘空间。
10.四、进程的状态:可运行、自愿休眠、非自愿休眠、挂起的进程、僵尸进程。
free 查看内存状态。
ps 查看进程。
pstree 以树状查看进程
top 显示、管理执行中的程序。
11、网络管理
Linux内核能够检测出全部连接的PCI设备,能够使用lspci命令验证计算机上的pci设备是否被内核检测到。Linux内核不容许用户以文件的形式访问网卡,也就是在/dev目录下无直接关联网卡的设备节点。Linux经过网络接口访问网卡,并以相似eth0的方式命令,其中字母表示数据链接技术,eth(以太网)、ppp(ppp协议的串口设备)、fddi。
ifconfig命令能够检验全部已识别的网络接口命令。
ifconfig eth0 能够只显示网络接口0的网络信息。
ifconfig eth0 down 禁用以太网0接口
ifconfig eth0 up 启用以太网0接口
11.一、静态路由配置
IP协议以使用路由器链接在一块儿的机器构成的网络为基础,全部链接到单一IP网络上的机器都有类似的IP地址,并一般使用相同的网络交换机。
每一个Linux内核都会有个路由表,路由表历来肯定对于一个发送出的数据包,内核使用哪一种方法传递数据包,路由表定义了哪一个网络接口与本地网络的关系,以及本地网络上充当连接外边网络的机器的身份标识。“Flags”列有G的表示的是网关。
route 命令查看路由表
route -n 路由表按IP地址来显示。
route add default gw IP ,增长新的网关
route del default gw IP ,删除网关
11.二、ARP配置
ARP协议(地址解析协议),基本功能是经过目标的IP地址,查询目标的MAC地址,ARP是IPv4网络层中不可缺乏的,IPv6中再也不适用。
arp 查看arp
11.三、网络测试
ping测试两台主机之间底层IP联通性
ping IP 直接pingIP地址。
nsloopup 检查DNS查询结果
网络抓包工具wireshark
12、DHCP
DHCP(动态主机配置协议),是一种网络管理员可以集中管理和自动分配IP网络地址的通讯协议。
十3、GCC编译器和GDB调试器
GCC编译器是GNU开源组织发布的Linux下多平台编译器,将多种语言编写的源程序编译、连接成可执行文件,GDB是调试器。
13.一、连接库
函数库其实是一些头文件(.h)或者库文件(.so或者.a)的集合。Linux下大多数头文件的默认路径是/usr/include,库文件默认路径是/usr/lib/,有时候使用GCC编译时须要为其指定所须要的头文件和库文件的路径。
GCC采用搜索目录的方法查找所须要的文件,-I选项能够向gcc头文件搜索路径中添加新的目录,假如在当前目录下编写了foo.c,而在/home/yang/include/目录下有编译改程序时所须要的头文件(不是在/usr/include/目录下),为了使GCC可以顺利找到,能够使用I选项:
gcc foo.c -I /home/yang/include -o foo
若是使用了不在标准库位置的库文件,能够使用-L选项向gcc库文件搜索路径中添加新的目录,假如在/home/yang/lib/目录有foo.c所须要的库文件。
gcc foo.c -L /home/yang/lib -lfoo -o foo
编译命令中,-l选项,指示gcc去连接库文件libfoo.so,库文件命名时有一个约定,以lib三个字母开头,所以在用-l选项指定连接库文件名时省去了lib三个字母,也就是说gcc对-lfool进行处理时,会自动搜索libfoo.so文件。
Linux下库文件分为两大类:动态连接库(以.so结尾)和静态连接库(一般以.a结尾),区别是所需的代码是在运行时动态加载的仍是编译时静态加载的。默认状况下gcc连接时优先使用动态连接库,只有在动态链接口不存在时才考虑使用静态连接库。若是连接库里同时有libfoo.so libfoo.a两个库文件,为了使用静态库文件,使用以下命令:
gcc foo.c -L /home/yang/lib -static -lfoo -o foo
13.二、同时编译多个源程序
若是一个程序有多个源文件组成,foo1.c foo2.c foo3.c 对他们编译生成foo可执行程序,命令以下:
gcc foo1.c foo2.c foo3.c -o foo 等价于下列命令:
gcc -c foo1.c -o foo1.o
gcc -c foo2.c -o foo2.o
gcc -c foo3.c -o foo3.o
gcc foo1.o foo2.o foo3.o -o foo
13.三、管道
GCC生成可执行文件时,须要通过预处理、编译、汇编、连接,几个步骤,并且每一个步骤都须要一个临时文件来保存信息,当源文件不少时将会增长系统的开销,能够使用管道来减少开销,
gcc -pipe foo.c -o foo
十4、make的使用和makefile的编写
make工程管理器是Linux下的一个“自动编译管理器”,“自动”是指它可以根据文件的时间戳,自动发现更新过的文件而减小程序编译的工做量,它经过读入Makefile文件的内容来执行大量的编译工做。
make机制的运行环境须要一个命令行程序make和一个文本文件Makefile。make是一个命令工具,用来解释makefile的命令。
假如一个程序 由main.c foo1.c foo2.c foo3.c 组成,makefile文件内容:
all: main.c foo1.c foo2.c foo3.c
gcc main.c foo1.c foo2.c foo3.c -o all
这5个文件应当存放在Linux的同一个目录下,使用make进行自动编译的时候,它会在这个目录下找到makefile文件,在存放文件的目录下输入make命令进行编译。
make是一个Linux下的二进制文件,自动寻找名称为Makefile的文件做为编译文件,若是没有则寻找makefile文件做为编译文件。
make操做管理Makefile文件的规则:
(1) 若是这个工程没有编译过,那么全部C文件都须要被编译和连接。
(2) 若是这个工程的某几个C文件被修改,则只需编译被修改过的C文件,并链接目标程序。
(3) 若是这个工程的头文件被修改了,则须要编译引用这个头文件的C文件,并链接至目标程序。
反斜杠“\”为换行符,某一条规则或命令不能在一行中写完时,能够用它表示换行。5.2程序能够保存为当前目录下的Makefile文件或makefile文件,或makefile文件夹下的文件,在该目录下直接输入命令make就能够自动生成可执行文件all,若是要删除可执行文件和全部的中间目标文件,执行make clean 命令就能够了。
在Makefile中,目标名称指定有如下惯例(固然能够不适用这些惯例):
all:表示编译全部内容,是执行make时默认的最终目标。
clean:表示清除全部的目标文件。
disclean:表示清除全部内容。
install:表示进行安装的内容。
5.2所示Makefile中,目标包含以下内容:最终可执行文件all和8个中间文件*.o;依赖文件即每一个冒号后边的那些.c和.h文件,每一个.o文件都有一组依赖文件,这些.o文件又是最终all的依赖文件,依赖关系及说明目标文件是由哪些文件生成。定义好依赖关系,后续的代码定义了生成目标的方法,注意必定要以一个Tab键作为开头。
14.一、makefile的书写规则
makefile书写包含两个:一个是依赖关系,一个是生成目标的方法。
makefile中的命令必须以tab键开头。
Makefile中的变量就像是c C++中的宏,表明了一个字符文本,在Makefile执行的时候就会展开,变量能够使用在目标、依赖目标,命令或是makefile的其余部分中。
变量的命名能够包含字符、数字、下划线(能够是数字开头),可是不能有 ‘:’’ #‘ ‘ =‘或是空格、回车,变量名区分大小写。变量在声明时须要给予赋初值,使用时须要在变量前边加上“$”符号,最好用小括号“()”或花括号"{}"把变量给括起来。若是要使用真实的“$”字符,那么须要用"$$"
除了使用“=”给变量赋值外,Makefile还支持嵌套定义,例如
执行make all 将会输出 Huh?,Makefile变量的这个特性有利有弊,好处是能够把变量真实值推到后面来定义如:
CFLAGS=$(include_dirs) -O
include_dirs=-Ifoo -Ibar
当CFLAGS在命令中被展开时,会是 -Ifoo -Ibar -O ,使用这种形式的弊端就是递归定义可能会出问题如:
A=$(B)
B=$(A)
这会让make陷入无限循环的变量展开过程当中去,make有能检测这样的定义,并报错,为了不无限循环,定义了另一种变量“:=”如:
x :=foo
y :=$(x) bar
x :=later
等价于
y := foo bar
x := later
":="操做符,使得前边的变量不能使用后面的变量,只能使用前面已经定义好了的变量,若是是这样:
y:=$(x) bar
x :=a
那么y的值是bar 而不是 a bar
“?=”操做符:foo?=bar,若是变量foo没有被定义过,那么变量foo的值就是bar,若是foo被定义过,那么这条语句什么都不作。等价于
ifeq($(origin foo),undefined)
foo=bar
endif
另一种操做符“+=”给变量追加值,如:
objects= main.o foo.o
objects +=another.o
等价于
objects= main.o foo.o
objects := $(objects) another.o
define 关键字:使用define关键字设置变量的值能够有换行,define指示符后面是变量的名字,另起一行定义变量的值,定义是以endef关键字结束,define中的命令也都是以Tab键开头,不然make将不把它当作命令。
define two-line
echo foo
echo $(bar)
endef
十5、文件的IO操做
有关I/O操做分为两类:基于文件描述符的IO操做,基于流的IO操做。
Linux中,文件提供了简单并一致的接口来处理系统服务与设备,全部的内容都被当作文件,全部的操做均可以归结为对文件的操做。操做系统能够像处理普通文件同样来使用磁盘文件,串口,键盘,显示器,打印机及其余设备。
普通文件:文本文件、二进制文件。普通文件能够直接查看,二级制文件不能打开。
目录文件:只有root用户能写目录文件,其余用户只能读。
设备文件:为操做系统和IO设备提供连接的一种文件,Linux把设备的IO做为普通文件读取和写入,操做内核提供对设备处理和对文件处理统一的接口,每一个IO设备都对应一个设备文件,存放在/dev目录 中。
连接文件:提供了一种共享文件的方法。
管道文件:用于进程间传递数据,是进程间通讯的一种机制。
套接口文件:在不一样计算机的进程间通讯也叫套接字。套接字是操做系统内核中的一个数据结构,是网络中节点进行通讯的关键。套接字有三种类型:流式套接字,数据报套接字,原始套接字。流式套接字也就是TCP套接字(面向链接的套接字),数据报套接字也就是UDP套接字(无链接的套接字),原始套接字用“SOCK_RAW”表示。
15.一、文件描述符
Linux用文件描述符来访问文件,文件描述符是一个非负整数,用于描述被打开的文件索引值。当内核打开或新建一个文件时,就会返回一个文件描述符。文件描述符0与标准输入相结合,文件描述符1与标准输出相结合,文件描述符2与标准出错相结合。POSIX中用STDIN_FILENO STDOUT_FILENO STDERR_FILENO来代替0、一、2.这三个符号常量位于头文件unistd.h
15.二、文件重定向
shell提供一种方法,任何一个或这三个描述符都能重定向都某一个文件,而不是默认的输入或输出设备。如:
ls>file.list
15.三、文件的建立、打开与关闭
对一个文件操做,首先要求这个文件存在,其次在操做以前将这个文件打开,这样才能对文件进行操做,操做完成后,必须将文件关闭。
(1) open 函数能够打开或建立一个文件,函数说明以下:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open(const char *pathname ,int flags) ; //打开一个如今文件
int open(const char *pathname ,int flags,mode_t mode); // 打开的文件不存在,则先建立它
返回:若成功,返回文件描述符,若出错返回-1.
参数pathname是一个字符串指针,它指向须要打开(或建立)文件的绝对路径或相对路径名。
参数flags用于描述打开文件的方式,以下表所示,定义在fcntl.h头文件中,flags的值能够由表中取值逻辑或获得。O_RDONLY,O_WRONLY,O_RDWR这三个参数只能出现一个。
参数mode用于指定所建立文件的权限,使用按位逻辑或的方法进行组合。
建立文件creat()函数,函数原型以下:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int creat(const char *pathname,mode_t mode);
返回:若成功,返回以只写方式打开的文件描述符,若出错返回-1. 参数pathname和mode与open函数的意义相同。
create等效于:open(pathname,O_WRNOLY|O_CREAT|O_TRUNC,mode);
creat的不足之处是以只写的方式打开所建立的文件,若是要建立一个临时文件,并要先写该文件而后读该文件,则必须先调用create、close,而后再调用open 。
(3)close函数
close函数用于关闭一个文件,函数说明以下:
#include <unistd.h>
int close(int fd);
返回:若成功返回0,出错返回-1.参数fd是需关闭文件的文件描述符。
(4) 文件的定位
每一个打开的文件都有一个与其相关联的“当前文件位移量”,它是一个非负整数,用以度量从文件开始处计算的字节数。打开一个文件时,除非指定O_APPEND选择项,不然该位移量被设置为0.能够调用lseek函数显示的定位一个打开文件,函数说明以下:
#include <sys/types.h>
#include <unistd.h>
off_t lseek(int fd,off_t offset,int whence); 返回:若成功,返回新的文件位移量,若出错为-1.“lseek”l表示长整型。
fd:文件描述符,offset 表示位移量大小单位字节,
(5) read函数
读写是文件操做的核心内容,实现文件的IO操做必须进其进行读写。read函数说明以下:
#include <unistd.h>
ssize_t read(int fd ,void *buff,size_t count);
返回:读到的字节数,若已读到文件尾返回0,若出错返回-1.
fd,文件描述符,buff存放读取的字节,count要读取数据的字节数。
读操做从当前位移量处开始,在成功返回以前,该位移量增长实际读获得的字节数。多种状况实际读到的比要读的少:
读普通文件时,在读到要求的个数字节以前读到了文件末尾,好比读到文件末尾读了30个字节,要求读100个字节,则read返回30,下一次再调用read时返回0.
从终端设备读时,一次最多读一行。
当从网络读时,网络中的缓冲机构可能形成返回值小于要求读的字节数。
某些面向记录的设备,例如磁带,一次返回一个记录。
(6) write函数
用write函数向打开的文件写数据,函数说明以下:
#include <unistd.h>
ssize_t write(int fd,void *buf,size_t count);
返回:一般与count值相同,不然出错。
对于普通文件,写操做从文件的当前位移量开始。若是打开文件时指定了O_APPEND选择项,则在每次写操做以前,将文件的位移量设置在文件的结尾处。
od -c 文件名路径,查看该文件的实际内容,命令行中的-c表示以字符的方式打印文件内容。
15.四、文件的属性
Linux的文件系统具备比较复杂的属性,包括文件访问权限、文件全部者,文件自己,文件长度等。
(1) 改变文件的访问权限
chmod、fchmod 这两个函数能够改变现存文件的权限。
#include <sys/types.h>
#include <sys/stat.h>
int chmod(const char *pathname,mode_t mode);
int fchmod(int fd,mode_t mode);
chmod函数在指定文件上进行操做,pathname是绝对路径或相对路径;fchmod对已经打开的文件进行操做,fd是文件描述符, mode是权限。
shell中直接用chmod命令改变文件权限 好比 chmod 755 文件绝对路径或相对路径。
(2) 改变文件全部者
用户能够调用chown 、fchown 、和lchown 来改变一个文件全部者识别号和组识别号。
#include<sys/types.h>
#include <sys/stat.h>
int chown(const char *pathname,uid_t owner,gid_t group);
int fchown(int fd,uid_t owner,gid_t group);
int lchown(const char *pathname,uid_t owner,gid_t group);
三个函数若成功返回0,失败返回-1. pathname 绝对路径或相对路径,owner 新的拥有者, group 新的组。
chown 修改指定文件的全部者和组。
fchown 修改已经打开的文件的全部者和组。
lchown 针对符号连接文件。
(3) 重命名
一个普通文件或者一个目录文件均可以被重命名,rename函数以下:
#include <stdio.h>
int rename(const char *oldname,const char *newname);
返回:若成功返回0,若出错返回-1. rename参数会将oldname所指定文件名称改成参数newname所指定的文件名称,若newname存在则会删除。oldname和newname指向同一个文件时不会作任何修改。
不能将一个目录文件重命名为它的子文件。
(4) 修改文件的长度
stat结构体成员st_size 包含了一字节为单位的文件的长度,此字段只对普通文件、目录文件和符号连接文件有意义。
对于普通文件,其文件长度能够是0.
对于目录文件,文件长度一般是一个数,例如16或512的整数倍。
对于连接文件,文件长度是在文件名中的实际字节数。
截短文件能够调用函数truncate 和ftruncate,说明以下:
#include <sys/types.h>
#include <unistd.h>
int truncate(const char *pathname,off_t len);
int ftruncate(int fd ,off_t len);
返回:若成功返回0,若出错返回-1.
15.五、 文件的其余操做
(1) stat、fstat、lstat函数
Linux系统中全部的文件都有一个对应的索引节点,该节点包含了文件的相关信息,这些信息保存子啊stat结构体中,可经过这三个函数进行查看。
#include <sys/types.h>
#include <sys/stat.h>
int stat(const char *pathname,struct stat *sbuf);
int stat(int fd,struct stat *sbuf);
int lstat(const char *pathname, struct stat *sbuf);
返回:成功返回0,出错返回-1.
头文件<sys/types.h>中定义了某系和实现有关的数据类型,被称为基本系统数据类型,头文件中的这些数据类型都是用typedef 定义的,绝大多数都以 _t 结尾。
(2) dup dup2函数
这两个函数用来服装一个现存的文件描述符。
#include <unistd.h>
int dup(int fd);
int dup2(int fd,int fd2);
(3) fcntl函数,能够改变已经打开的文件的性质。
15.五、特殊文件的操做
(1) 建立目录 mkdir
(2) 删除空目录 rmdir
(3)opendir closedir readdir
十6、基于流的IO操做
流IO是C语音的标准库提供的,这些IO能够代替系统中提供的read和write函数。
流和FILE对象:上一章对IO操做是基于文件描述符的,打开文件返回文件描述符,而后基于文件描述符对文件进行操做。对于标准的IO库,操做则是基于流进行。用标准的IO打开或建立一个文件是,已经使一个流和一个文件相结合。
打开一个流时,标准IO函数fopen返回一个指向FILE的指针。对流的IO操做相似对文件描述符的IO操做,调用fopen函数打开一个文件,并返回一个FILE指针,流成功打开后,就能够调用标准IO进行操做 。当完成操做后,须要执行清空缓冲、保存数据等操做。而后将流关闭,若是不关闭流,可能形成数据的丢失,fclose().
16.一、标准输入、标准输出、标准出错
使用流IO时,会自动打开标准输入、标准输出、标准出错。文件描述符用STDIN_FILENO STDOUT_FILENO STDERR_FILENO 来表示,这三个符号常量在<unistd.h>中。
基于流IO是,经过预约义文件指针,stdin stdout stderr来引用标准输入、标准输出、标准出错的,定义在头文件<stdio.h>中。
16.二、 缓存
基于流的操做最终会调用read和write函数进行IO操做。为了尽量减小使用read和write函数的次数,流对象一般会提供缓冲区(缓存),标准IO提供了3中类型的缓存:
全缓存:直到缓冲区被填满,才调用系统IO函数。
行缓存:直到遇到换行符“\n”才进行IO操做。
无缓存:数据会当即读入或输出到外存文件或设备上。
16.三、设置缓存的属性
缓存具备本身的属性,包括缓冲区的类型和缓冲区的大小。调用fopen打开一个流时,就开辟了缓冲区,系统会赋予其一个默认的属性值。也能够根据本身需求来设定缓冲区的属性值,调用以下函数:
#include <stdio.h>
void setbuf(FILE *fp,char *buf);
void setbuffer(FILE *fp,char *buf,size_t size);
void setlinebuf(FILE *fp);
int setvbuf(FILE *fp,char *buf,int mode,size_t size); 返回:0 成功,非0 失败
这四个函数对流属性进行操做,操做对象是一个已经打开的流。
fp 指向FILE结构体的指针。
setbuf 用于将缓冲区设置为全缓存或无缓存,参数buf执行缓冲区的指针。buf指向一个真实缓冲区地址时,此函数将缓冲区设置为全缓冲,大小由预约义常数BUFSIZ指定,当buf为NULL时,设置为无缓冲,此函数,当作激活或禁止缓冲区的开关。
setbuffer的功能和使用方法与setbuf相似,区别是有程序员指定缓冲区的大小,由size肯定。
setlinebuf 用于将缓冲区设定为行缓存。
setvbuf 比较灵活,fp buf size含义与setbuffer函数相同,mode用于指定缓冲区类型,_IOFBF全缓存、_IOLBF 行缓存、_IONBF 无缓存。三个常量在<stdio.h>中,设定为_IONBF时参数buf和size是没用的。
最好在打开流还没对流操做以前,设置流的属性。
16.四、缓存的冲洗
冲洗,就是将IO操做写入缓存中的内容清空,清空能够是将缓存区内容丢掉也能够是保存到文件中,相应库函数以下:
#include<stido.h>
int fflush(FILE * fp);
#include<stdio_ext.h>
void fpurge(FILE *fp);
fflush函数将缓存区还没有吸入文件的数据强制性写入文件中,成功返回0,失败返回EOF。
fpurge函数,用于将缓冲区中的数据彻底清除。
16.五、流的打开与关闭
对一个流操做以前,先将他打开,也就是创建某一个流同某个文件或设备的关联,只有这样才能对这个流进行操做。打开流函数以下:
#include <stdio.h>
FILE *fopen(const char *pathname,const char *type);
FILE *freopen(const char *pahtname,const char *type,FILE *fp);
FILE *fdopen(int fd,const char *type);
三个函数若成功返回文件指针,若出错则为NULL。
三个函数的区别有如下几点:
fopen 打开一个文件由pathname指定文件。
freopen 在一个特定流(有fp指示)打开一个指定的文件(路径名有pathname指示),若该流已经打开则先关闭。此函数用于将一个指定的文件打开为一个预约义的流:标准输入、标准输出,或标准出错。
fdopen 取一个现存的文件描述符,并使一个标准的IO流与该描述符相结合。此函数经常使用于由建立管道和网络通讯通道函数得到的描述符,由于这些特殊类型文件不能使用标准的IOfopen函数。
type参数,指定了该IO流的读写方式,该值以一个字符串的形式传入。
type 取值字符串中包含 a的表示 追加写,即流打开之后,文件的读写位置在文件的末尾。type 字符串中包括字母b的表示流以二进制的形式打开,其余的则表示以文本的形式打开。对于Linux系统来讲没有意义,由于Linux系统下,二进制文件和文本文件都是普通文件,是字节流。
fopen打开成功返回文件指针,若出错则返回NULL,出错缘由有如下三种:
指定路径有错误
type参数是一个非法的字符串
文件的操做权限不够。
fdopen函数用在一个已经打开的文件描述符上打开一个流。与fopen不一样,因为文件已经打开,fdopen不会建立文件,也不会将文件截短为0.
(2) 流的关闭
在所需的操做完成之后,必须将流关闭。fclose用于关闭一个流,函数以下:
#include <stdio.h>
int fclose(FILE *fp);
若成功则返回0,若失败则返回EOF(-1,定义在stdio.h)。
对流的操做完成后,必须关闭它,大多数流的操做都是基于缓冲机制的,fclose在关闭流以前会将缓冲区的内容写入文件或者设备。fclose若是关闭的是本地文件,出错的概率很小,若是关闭的是一个网络环境中的远程文件,fclose函数就有可能出错,这时就要检查返回值了。
15.六、流的读写
打开了流,则可在4种不一样类型的IO进行选择,对其进行读、写操做。
基于字符的IO:每次读写一个字符数据的IO方式,若是流是带缓存的,则由标准IO函数处理全部缓存。
基于行的IO:当输入内容遇到‘\n’换行符的时候,则将换行符以前的内容送到缓冲区IO中的方式成为基于行的IO。
直接IO:输入输出操做以记录为单位进行读写。
格式化IO:printf scanf 函数。
(1) 基于字符的IO
基于字符的IO一般是处理单个字符的。如下3个函数用于读入一个字符:
# include <stdio.h>
int getc(FILE *fp);
int fgetc(FILE *fp);
int getchar(void);
返回:若成功则返回读入字符的值,若已处文件尾端或出错则为EOF。
前两个函数中,参数fp表示要读入字符的文件,getc可被实现为宏,fgetc不能实现为宏。getc的参数不能是具备反作用的表达式。(反作用表达式:经过++ 等操做改变参数的值)
getchar只能用来从标准输入输出流总输入数据,至关于调用以stdin为参数的getc函数即,getc(stdin) 。
这三个函数以unsigned char 类型转换为int的方式返回下一个字符。
(2) 字符的输出
如下三个函数用于字符的输出:
#include <stdio.h>
int putc(int c FILE *fp);
int fputc(int c ,FILE *fp);
int putchar(int c);
返回: 若成功则为C,若出错则为EOF。
putc和fputc第一个字符表示要输出的字符,第二个参数表示输出的文件,若是成功输出一个字符,则返回输出的字符,若出错则返回EOF。
与输入函数同样,putchar(c)等同于putc(c,stdout);putc可被实现为宏,fputc不能实现为宏。
(3) 基于行的IO
当输入内容遇到‘\n’换行符的时候,则将流中\n以前的内容送到缓冲区的IO方式成为基于行的IO。
行的输入:
fgets和gets函数实现输入一行字符串,函数以下:
#include <stdio.h>
char *fgets(char *buf,int n,FILE *fp);
char *gets(char *buf);
返回:若成功返回缓冲区首地址,若已处文件尾或者出错则为NULL。
fgets函数的第一个参数表示存放读入串的缓冲区,第二个参数n表示读入字符个数,不能超过缓存区长度。fgets函数一直读知道遇到一个换行符为止,若是在n-1个字符内未遇到换行符,最后一个字节用于存放字符串结束标志\0 ,fgets函数会将换行符存入缓冲区。
gets函数从标准输入读取一行并将其存入一个缓冲区。
行的输出:
fputs和puts 函数实现输出一行字符串,函数原型以下:
#include <stdio.h>
int fputs(const char *buf,FILE *restrict fp);
int puts(const char *str);
fputs第一个参数表示存放输出内容的缓冲区,第二参数表示要输出的文件。成功返回输出的字节数,失败返回-1.
puts 用于向标准输出输出一行字符串。
(3)直接IO
字符读写和行的读写函数是以一个字节或一次一行的方式进行IO操做,好比一次读或写整个机构,为了使用getc或putc,必须循环整个机构,一次读或写一个字节,fputs遇到null或换行符字节就中止, 二进制IO操做解决了这个问题:
#include <stdio.h>
size_t fread(void *ptr,size_t size,size_t nmenb,FILE *fp);
size_t fwrite(void *ptr,size_t,size_t nmenb,FILE*fp);
ptr 缓冲区指针,size 目标文件的大小,nmemb 欲读取或写入的字节个数,fp文件指针。
格式化的IO:
格式化IO是IO最多见的IO方式,好比printf 和scanf
格式化输出有4个printf函数:
#include <stdio.h>
int printf(const char *format,...);
int fprintf(FILE *fp,const char *format,...);
两个函数的返回,若成功返回实际输出的字节数,若出错为负值。
int sprintf(char *st,const char *fromat,...);
int snprintf(char *st,size_t size,const char *format,...);
格式化输入的3个scanf函数:
#include <stdio.h>
int scanf(const char *format,...);
int fscanf(FILE *fp,const char *format,...);
int sscanf(char *str,const char *format,...);
十6、进程控制
进程是一个程序的一次执行过程,程序是进程的一种静态描述,系统中运行的每一个程序都是在它的进程中运行的。进程:在自身虚拟空间运行的一个单独的程序。进程的要素:有一段程序供进程运行,专用的系统堆栈空间,进程控制块(task_struct),独立的存储空间。进程缺乏一个要素时,咱们成其为线程。
Linux系统中全部的进程都是由一个进程号为1的init进程衍生而来的。Linux有3中进程:交互进程(shell)、批处理进程,监控进程(守护进程)。
每一个进程在建立时都会被分配一个数据结构,成为进程控制块(process control block ,PCB)。PCB包括一些信息:进程标识符,进程当前状态,进程相应的程序和数据地址,进程资源清单,进程优先级,CPU现场保护区,进程同步与通讯机制,进程所在队列PCB的连接字,与进程相关的其余信息。进程ID(PID)是一个非负整数范围 0--32767,Linux的专用进程:ID 0 是调度进程,经常成为交换进程。ID1 是init进程,UNIX早期版本中是/etc/init 新版本是/sbin/int。该进程负责在内核自举后启动一个Unix系统。inti一般读与系统有关的初始化文件/etc/rc*,并将系统引导到一个状态,init进程不会终止。一个或多个进程合起来构成进程组,一个或多个进程组合起来构成一个会话。这样能够对进程进行批量操做。
ps 查看本身系统中目前有多少个进程,ps -aux 列出系统中进程的详细信息。
Linux 提供getpid函数来返回系统当前前程的PID,函数以下:
#include <sys/types.h>
#include <unistd.h>
pid_t getpid(void);
16.一、进程的控制是经过函数调用实现的,其中包括系统调用函数也包括库函数。接下来学习进程的建立、等待、终止等具体操做的相关函数调用。
(1) fork 和vfork 函数
建立一个进程,最基本的系统调用是fork,系统用fork派生一个进程,函数以下:
#include <sys/types.h>
#include <unistd.h>
pid_t fork(void);
返回: 若成功,父进程中返回子进程ID,子进程中返回0,若出错返回-1.
fork的做用是复制一个进程。子进程是父进程的复制,即子进程从父进程获得了数据段和堆栈的复制,这些须要分配新的内存,而只读的代码段,一般使用共享内存的方式访问。
fork函数的用途:一个进程但愿复制自身,从而父子进程能执行不一样段的代码,进程想执行另一个程序。建立新进城后会返回给父进程子进程的ID,由于没有一个函数获得一个父进程全部子进程的ID,子进程返回0,由于子进程能够经过调用getppid()函数获得父进程的 pid。在fork以后是进入父进程仍是子进程不肯定。
Linux中建立新进程的方法只有一个,就是fork ,system()最后调用的也是fork。
另外一个建立进程的方法vfork,函数以下:
#include <sys/types.h>
#include <unistd.h>
pid_t vfork(void);
返回和fork同样:父进程中返回子进程的ID,子进程返回0,返回-1错误。
fork和vfork区别:fork要复制父进程的数据段,vfork不须要彻底复制父进程的数据段,在子进程没有调用exec或exit以前,共享数据段。fork不对父子进程的执行顺序进行任何限制,在vfork调用中,子进程先运行父进程挂起,子进程调用exec或exit以后父进程的执行次序才再也不有限制。
(2) exec() 函数
Linux使用exec函数来执行新的程序,以新的子进程彻底代替原有的进程,exec是一个函数族,指的是一组函数,一共有6个:
#include <unistd.h>
int execl(const char *pathnaem,const char *arg,...);
int execlp(const char *filename,const char *arg,...);
int execle(const char *pathname,const char *arg,...,char *const envp[]);
int execv(const char *pathname, char *const argv[]);
int execvp(const char *filename,char *const argv[]);
int execve(const char *pathname,char *const argv[],char *const envp[]);
返回:若成功无返回值,若出错 -1
函数命中含有字母“l”的,其参数个数不定,参数由所调用程序的命令行参数列表组成,最后一个NULL表示结束。
函数名中含有字母“v”的,则是使用一个字符串数组指针argv指向参数列表,这一字符串数组和含有字母“l”的函数中的参数彻底相同,一样以“NULL”结束。
函数名中含有字母“p”的函数能够自动在环境变量PATH指定的路径中搜索要执行的程序,所以它的第一个参数为filename,表示可执行函数的文件名。而其余函数须要用户在参数列表中指定该程序路径,因此其第一个参数为pathname。
函数名中有字母“e”的,比其余函数多含有一个参数envp,这是一个字符串数组指针,用于指定环境变量。调用函数execle,execve 时,用户自行设定子程序的环境变量,存放在参数envp所指定的字符串数组中,这个字符串数组也必须由NULL结束。其余函数则是接收当前环境变量。
execve才是真正意义上的系统调用,其余都是在此基础上通过包装的库函数。exec函数族做用是根据指定的文件名找到可执行文件,并用它来取代调用进程的内容,也就是在调用进程内部执行一个可执行文件。这里的可执行文件既能够是二进制文件,也但是任何Linux下可执行的脚本文件。
exec函数族的函数执行成功后不会返回,由于调用进程的实体,包括代码段,数据段和堆栈等都已经被新的内容取代,只是进程ID等一些表面上的信息保持原样。若是调用失败了,才会返回-1,从原程序的调用点接着往下执行。
当有程序认为不能作贡献了,它能够调用任何一个exec,让本身以新的面貌重生。广泛状况是,若是进程想执行另外一个程序,它就能够fork一个新进程,而后调用任何一个exec,这样看起来好像经过执行应用程序而产生了一个新进程同样。
fork调用进程的数据段和堆栈会复制到新的子进程,而fork以后咱们调用exec函数会将复制过来的东西会被抹掉,很浪费时间,因而设计了一种copy on write技术,fork结束后并不当即复制父进程内容,到了真正实用的时候才复制。
理解exec:
实际的main函数 int main(int argc,char *argv[],char *envp[]);
参数argc指出了运行该程序时命令行参数的个数,数组argv存放了全部命令行参数,数组envp存放了全部的环境变量。环境变量指的是一组值,从用户登陆后就一直存在,不少应用程序须要依靠它来肯定系统的一些细节,最多见的环境变量是PATH,它指出了应到哪里去搜索应用程序,如/bin HOME也是比较常见的环境变量,她指出了咱们在系统中的 我的目录。环境变量通常以字符串“XXX=xxx”的形式存在,XXX表示变量名,xxx表示变量值。
argv数组和argvp数组存放的都是指向字符串的指针,这两个数组都以一个NULL元素表示数组的结尾。
(3) exit()和_exit() 函数
系统调用是用来终止一个进程的,执行到exit系统调用,进程就会中止剩下的全部操做,清除包括PCB在内的各类数据结构,并终止本进程的运行,函数原型:
#include <stdlib.h>
_exit()函数用于正常终止一个程序,函数原型:
#include <stdlib.h>
void _exit(int status);
status取值:0 表示没有意外的正常结束;其余数值表示出现了错误,进程非正常结束,实际编程时能够用wait系统调用接收子进程的返回值。
区别:_exit()当即进入内核,exit先执行一些清除处理(包括调用执行终止处理程序,关闭标准的IO等)而后进入内核。
一个进程调用了exit后,该进程并不立刻消失,而是留下一个成为僵尸进程的数据结构,不占用内存。
(3) wait 和waitpid 函数
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *status);
pid_t waitpid(pid_t pid,int *status,int options);
若成功返回进程ID,失败返回-1。
进程一旦调用了wait,就当即阻塞本身,有wait自动分析是否当前进程的某个子进程已经退出,若是让它找到一个僵尸子进程,wait就会收集这个子进程的信息,并把它完全销毁后返回;若是没有找到这样一个子进程,wait就会一直阻塞在这里,只有有一个出现为止。
参数status用来保存被收集进程退出时的一些状态,它是一个指向int类型的指针。若是对这个子进程是若是死掉的绝不关心,则能够设定这个参数为NULL。
pid=wait(NULL);
若是成功,wait会返回被收集的子进程ID,若是调用进程没有子进程,调用就会失败,返回-1,errno被置位ECHILD。
wait和waitpid做用相同,waitpid用来指定等待的进程,能够使进程不挂起而当即返回。参数pid指定所等待进程,
options提供了一些额外的选项来控制waitpid,Linux支持WNOHANG WUNTRACED,能够使用|将这两个参数连接起来,也能够设置为0.
进程简述:fork执行产生了一个和父进程同样的进程(数据段、堆栈,共享代码段),随着exec执行,新进程金蝉脱壳,开始一个全新的进程,并替代原来的进程。进程结束能够天然结束或被其余进程结束:本身结束执行到main}或者调用exit函数(留下僵尸进程)、return函数,wait、_wait函数清除掉僵尸进程。
(5) 用户ID和组ID。
与某一进程相关联的ID有6个:实际用户ID、实际组ID、有效用户ID、有效组ID、保存的设置用户ID、保存的设置组ID,一般,有效用户ID等于实际用户ID,有效组ID等于实际组ID。相关函数:
#include <sys/types.h>
#include <unistd.h>
uid_t getuid(void);
gid_t getgid(void);
gid_t getegid(void);
uid_t gettuid(void);
返回:进程的相关用户ID。
getuid用于得到实际用户标识符,getgid得到实际的组ID,gettuid得到有效的组ID,getegid得到有效的组标识符。
(6) system 函数
system函数是一个和操做系统先关的函数,用户能够使用它在本身的程序中调用系统提供的各类命令。system函数原型:
#include <stdlib.h>
int system(const char *cmdstring);
十7、信号
信号是进程间通讯的机制,信号不是将数据发送给某一进程,而是用于通知一个进程某一个特定事件的发生。信号全称为软中断信号,也叫软中断。软中断信号用来通知进程发生了异步事件,进程之间能够互相经过系统调用kill()发送软中断信号,内核也能够给进程发送信号。信号用来通知某个进程发生了某个事件,并不给进程传送数据。
进程处理信号的方法:(1)相似于中断的处理程序,对于须要处理的信号,进程能够指定处理函数。(2)忽略某个信号,对信号不作任何处理。(3) 对该信号的处理保留系统的默认值,大多数是使得进程终止,进程经过系统调用signal()来指定进程对某个信号的处理。
进程表的表项中有一个软中断信号域,该域中的每个位对应一个信号,当有信号发给进程时对应位置位。进程对不一样的信号能够同时保留,对于同一个信号,进程并不知道来过多少个。
每一个信号都有一个名字,都以SIG开头。例如SIGABRT是夭折信号,进程调用abort()函数时产生这种信号。SIGALRM是闹钟信号,alarm()函数设置的时间超事后产生此信号。头文件<signal.h>中,这些信号都被定义为正整数,成为信号编号,编号为0的成为空信号。
shell下键入kill -l 或者man 7 signal 查看信号。
17.一、内核对信号的处理
内核给进程发送软中断的方法:在进程所在的进程表中的信号域设置对应的位(内核经过在进程struct task_struct结构中信号域中设置相应的位来实现向进程发送一个信号)。进程检查是否收到信号的时机:进程即将从内核态返回用户态时,因此进程处于内核态时软中断信号不当即起做用,进程要返回用户态时先处理完信号才返回用户态,或者一个进程要进入或者离开一个适当的低优先级睡眠状态时。
17.二、信号操做的相关函数
(1) signal函数
要对一个信号进行处理,须要给出此信号发生时系统所调用的处理,能够做为一个特定的信号注册相应的处理函数。若是源程序注册了针对某一个特定信号的处理程序,不论当时程序执行到何处,一旦进程接收到该信号,相应的调用就会发生,调用signal函数来注册某个特定信号的处理程序,函数以下:
#include <signal.h>
void (*signal(int signum,void (*handler)(int)))(int);
返回:若成功则返回之前的信号处理配置,若出错则为SIG_ERR
参数signum,所注册函数对应的信号名,handler的取指:常数SIG_IGN、常数SIG_DFL或接到此信号后要调用的函数的地址。若是指定SIG_IGN,则向内核表示忽略此信号(SIGKILL SIGSTOP不能忽略),若是指定SIG_DFL表示接收到此信号后的动做是系统默认动做。当指定函数地址时,我称此为捕捉此信号,成函数为信号处理程序或信号捕捉函数。
signal函数有两个参数,返回一个函数指针,signum是一个整型数,第二个参数是函数指针,它指向的函数须要一个整形参数,无返回值。
<signal.h>中 #deifne SIG_ERR -1 #define SIG_DFL 0 #define SIG_IGN 1
(2) sigaction函数
sigaction函数的功能是检查或修改与指定信号相关联的处理动做,此函数能够彻底替代signal函数,sigaction函数以下:
#include <signal.h>
int sigaction(int signum,const struct sigaction *act,struct sigaction *oldact);
返回:成功返回0,出错返回-1.
signum是要捕捉的信号。act是一个结构体,里边包含了信号处理函数的地址、处理方式等信息。参数oldact是一个传出参数,sigaction调用成功后,oldact里边包含之前对signum信号的处理方式的信息。
struct sigaction
{
void(*sa_hanlder)(int)
void (*sa_sigaction)(int,siginfo_t *,void *);
sigset_t sa_mask;
int sa_flags;
void (*sa_restore)(void);
}
字段sa_handler是一个函数指针,用于指向原型为void handler(int)的信号处理函数地址,即老类型的信号处理函数。
字段sa_sigaciton是一个函数指针,指向void handler(int iSignNum,siginfo_t *pSiginfo,void *pReserved);的信号处理函数,新类型信号处理函数。该函数三个参数意义: iSigNum传入的信号,pSiginfo与该信号相关的一些信息,是个结构体。pReserve的,保留。
字段sa_handler sa_sigaction应该只有一个有效,若是用老信号处理机制,让sa_handler指向正确的函数,若是用新的信号处理机制,让sa_sigaction指向正确处理函数,并让sa_flags包含SA_SIGINFO选项。
sa_mask是一个包含信号集合的结构体,表示被阻塞的信号。
(3)信号集
为了方便同时对多个信号进行处理,Linux系统中引入了信号集的概念。 信号集用于表示多个信号所组成集合的数据类型,信号集定义为sigset_t类型的变量,5个处理信号集的函数:
#include <signal.h>
int sigemptyset(sigset_t *set); 将set指向的信号集设定为空,不包含任何信号。
int sigfillset(sigset_t *set); 将set指定的信号集设定为满,即包含全部信号。
int sigaddset(sigset_t *set,int signum); 将signum所表明的信号添加到set指定的信号集。
int sigdelset(sigset_t *set,int signum); 将signum表明的信号从set信号集中删除。
返回:成功返回0,错误返回-1.
#include <signal.h>
int sigismember(const sigset_t *set,int signum); 检查signum表明的信号是否存在于set信号集中。
返回:若为真返回1,为假返回0.
set 指向信号集的指针,signum表示一个信号。
(4) 信号的发送
发送信号函数:kill raise sigque alarm setitimer abort 。
kill 函数用于向某一给定进程或进程组发送信号,函数以下:
#include <signal.h>
#include <sys/types.h>
int kill(pid_t pid, int signum); 返回:成功返回0,出错返回-1.
pid表示进程或进程组的编号,signum发送的信号。若是signum0 能够检查进程是否存在。
raise 函数用于向进程自己发送信号,函数以下:
#include <signal.h>
#include <sys/types.h>
int raise(int signum); 返回:0成功, -1 错误。
sigqueue函数
sigqueue函数是针对实时信号提出的,支持信号带有参数,一般与函数sigaction配合使用,函数以下:
#include <signal.h>
#include <unistd.h>
int sigqueue(pid_t pid,int signum,const union sigval val); 若成功返回0,出错返回-1.
pid是指定信号的进程ID,signum 将发送的信号,union signal 是一个联合数据结构,指定了信号传递的参数,即4字节值,定义以下:
typedef union sigval
{
int sival int;
void *sigval_ptr;
} sigval_t;
sigqueue比kill传递了跟多的附加信息,单sigqueue只能向一个进程发送信号,而不能发送信号给一个进程组。若是signum=0将会执行错误检查,但实际上不发送任何信号,
十8、进程间通讯
进程间通讯(InterProgress Communication,IPC)就是在不一样进程之间传播或交换信息。进程的空间是相互独立的,按说是不能相互访问,惟一的例外是共享内存区,内核能够提供共享内存的条件。
Linux的进程间通讯的方法有管道、消息队列、信号量、共享内存区、套接口等。管道分为命名管道、无名管道。消息队列、信号量、共享内存成为系统IPC。管道、消息队列、信号量和共享内存用于本地进程间的通讯,套接口用于远程进程间通讯。
管道(pipe)及命名管道(named pipe):管道用于亲缘关系进程间的通讯,命名管道克服了管道没有名字的限制,除具备管道的全部功能外,还用于无亲缘关系进程间的通讯。
进程间通讯就是让多个进程之间相互访问,这种访问包括程序运行时适时的数据,也包括对方的代码段。
18.一、管道
管道(pipe)也叫匿名管道,是在两个进程之间实现一个数据流通的通道。至关于文件系统上的一个文件,来缓存所须要的数据。略区别于文件,管道中的数据读出后,管道中就没有数据了。管道会随着进程的结束而被系统清除,建立一个管道时生成两个文件描述符,对于管道所使用的文件描述符并无路径名。常用|来连接连个命令。
管道从数据流上全双工管道和半双工管道,管道没有命名的成为匿名管道,管道是半双工的,数据只能向一个方向流动。只能用于父子进程和兄弟进程之间。单独构成一个独立的文件系统。数据的读出和写入。管道的缓冲区是有限制的。管道传送的是无格式字节流,要求管道的读出和写入房必须事先约定好数据格式。
Linux下使用pipe函数建立一个匿名管道,函数原型以下:
#include <unistd.h>
int pipe(int fd[2]);
返回:若成功则返回0,若出错则返回-1.
参数fd[2]是个长度为2的文件描述符组,fd[0]是读出端的文件描述符,fd[1]是写入段的文件描述符。函数成功返回后,则自动维护一个从fd[1]到 fd[0]的数据管道。管道的关闭则使用基于文件描述符的close函数。
能够使用read和write函数对管道进行操做,管道的读出端只能读数据管道的输入端只能输入数据,若是从输入端读或者从输出端写都会出错,通常的IO操做函数均可以用于管道,open close write read等。
对一个读端已经关闭的管道进程操做是,会产生SIGPIPE,说明管道读端已经关闭,而且write操做返回-1,error值设为EPIPE,对于SIGPIPE信号进行捕捉处理。
若是要创建一个父进程到子进程的数据通道,能够先调用pipe函数紧接着调用fork函数,因为子进程会自动继承父进程的数据段,则父子进程同时拥有管道的操做权,管道的方向取决于用户怎么维护该管道。
要创建一个父进程到子进程的数据通道,也就是在子进程读出以前在父进程中写入数据,那么要在父进程中关闭管道的输出端,相应的在父进程中关闭管道的写入端,当维护子进程到父进程的数据通道时,父进程中关闭写入端,子进程中关闭读出端。使用pipe及fork组合,能够构造全部的父进程与子进程或子进程到兄弟进程的管道。
(2) 命名管道
命名管道也成为FIFO,它是一种文件类型,在文件系统中能够找到它,建立一个FIFO相似于建立一个文件。在程序中能够经过查看文件stat结构体中的st_mode成员的值来判断该文件是否为FIFO。即便不存在亲缘关系的进程也能够经过FIFO中路径名进行交互。
FIFO遵照先进先出的规则,对管道及FIFO的读老是从开始处返回数据,对它们写则把数据添加到末尾,不支持Sleek等文件定位操做。shell中能够使用mkfifo命令创建一个命名管道, mkfifo [option] name ... option选择中选择要建立FIFO的模式,使用形式为 -m mode,这里的mode指出将要建立FIFO的八进制模式。
建立FIFO相似于建立一个普通文件,FIFO文件能够经过文件名来访问,函数原型以下:
#include<sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname,mode_t mode);
返回:成功返回0,错误返回-1.
第一个参数路径名,也就是FIFO文件的名字,第二个参数与open函数中的mode参数相同。若是mkfifo的第一个参数是一个已经存在的路径名时,则返回EEXIST错误,典型的调用会先判断是否返回该错误,若是返回,则直接打开FIFO就能够了。FIFO文件隐形的规定不具备执行权限。
(3) 命名管道的读写
系统调用open打开一个命名管道,使用read和write函数对命名管道进行读写,close关闭一个管道,unlink删除一个命名管道。
(4) 消息队列
消息队列是一种以链表式结构组织的一组数据,存放在内核中,由各进程经过消息队列标识符来引用。管道是随进程持续的,消息队列是随内核持续的。
消息队列类型:POSIX消息队列及System V 消息队列,System 消息队列目前被大量使用。system V消息队列是随内核持续的,只有在内核重启或者显示删除一个消息队列时,该消息队列才会真正删除。系统中记录消息队列的数据结构(struct ipc_ids msg_ids)位于内核中,消息中全部消息对垒均可以在结构msg_ids中找到访问入口。
消息队列就是一个消息的链表。每一个消息队列都有一个队列头,用结构struct msg_queue来描述,队列头包含了消息队列键值、用户ID、组ID、消息队列中消息数目等。
(1) 消息队列的建立与打开
消息队列的内核持续性要求每一个消息队列在系统范围内都对应惟一的键值,要得到一个消息队列的引用标识符(ID)----即建立或打开消息队列,只须要提供该消息的键值便可。
得到特定文件名的键值的系统调用是ftok,函数以下:
#include <sys/types.h>
#include <sys/ipc.h>
key_t tfok (char *pathname,char proj);
返回:若成功则返回一个消息队列的键值,若失败则返回-1. 该函数并不直接对消息队列进行操做,但在调用msgget() 函数得到消息队列标识符前,调用该函数。
建立或打开一个消息队列的系统调用为msgget,函数原型以下:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgget(key_t key,int msgflag);
返回:若成功则为消息队列的引用标识符(ID),若失败则返回-1. 参数key是一个键值,由ftok得到,msgflg参数是一些标志位,能够取下值:IPC_CREAT、IPC_EXCL/IPC_NOWAIT或三者的逻辑或结果。
如下状况将会建立一个新的消息队列:
若是没有消息队列与键值key相对应,而且msgflg包含了IPC_CREAT标志位。
key参数为IPC_PRIVATE (设置成该标志并非其余进程不能访问该消息队列,只意味着将建立新的消息队列。)
(2) 消息队列的读写
使用消息队列进行进程间通讯,要对消息队列进行读和写的操做,写操做即向消息队列中发送数据,读操做即从消息队列中读出数据。
消息队列由两部分组成:消息类型和所传递数据,用数据结构struct msgbuf 来表示,消息类型一般是一个长整数。设定一个传递1024个字节长度的消息,可将结构定义以下:
struct msgbuf
{
long msgtype; // 消息类型,消息队列中读取消息的依据
char msgtext[1024]; // 消息内容,大小可调整
}
对于发送消息,首先预制一个msgbuf缓冲区并写入消息类型,调用响应的发送函数便可;对读消息来讲,首先分配一个msgbuf缓冲区,把消息读入缓冲区便可。
向消息队列发送数据;
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgsnd(int msgid,const void *prt,size_t nbytes,int flags);
返回:若成功返回0,出错返回-1.
msgsnd向一个消息队列发送一个消息,该消息被追加到队列的末尾。msgid表明队列的标识符,prt指向要发送的消息,nbytes 数据长度,flags用于指定消息队列满时的处理方法。对于发消息来讲,有意义的flags标志位IPC_NOWAIT,指明在消息队列没有足够空间发送消息时,msgsnd是否等待。当消息队列满时,若是设置了IPC_NOWAIT位,则马上出错返回,不然发送消息的进程被阻塞,直至消息队列中有空间或消息队列被删除时,函数马上返回。
形成msgsnd等待的条件有两种: 当前的大小与消息队列中的字节个数超过消息队列的总容量。 消息队列中的消息数不小于消息队列的总容量。
msgsnd 解除阻塞的条件有3个:不知足上述两个条件。msqid表明的消息队列被删除。调用msgsnd的进程被某个信号中断。
从消息队列中接收数据,函数原型:
#include <sys/types.h>
#include <sys/msg.h>
#include <sys/ipc.h>
int msgrcv(int msqid,void *prt ,size_t nbytes,long type ,int flags);
返回:成功返回消息的数据长度,若出错则返回-1.
此函数用于从指定消息队列中读取一个消息数据。msqid表明消息队列的引用标识符,prt 缓冲区,nbytes 字节个数,flags消息队列满时的处理方法。
得到或设置消息队列的属性:
消息队列的信息基本上都保存在消息队列头中,分配一个相似于消息队列头结构struct msqid_ds来返回消息队列属性;keil设置该数据结构,函数以下:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgctl(int msqid,int cmd ,struct msqid_ds *buf);
返回:成功返回0,不然返回-1.
系统调用对由msgid表示的消息队列执行cmd操做,cmd操做有三种:IPC_STAT IPC_SET IPCRMID.
IPC_STAT:用来获取队列消息,返回的信息存贮在buf指向的msqid_ds结构中。
IPC_SET : 该命令用设置消息队列属性,属性包括msg_perm.uid msg_perm.pid msg_perm.mode msg_qbytes同时影响msg_ctime 成员。
IPC_RMID:删除msqid消息队列。
18.五、共享内存
共享内存是linux下最快速最有效的进程间通讯方式。两个不一样进程A、B共享内存的意思是,同一物理内存被映射到进程A、B各自的进程地址空间。进程A能够即时看到进程B对共享内存数据的更新,反之B也能够看到A。
二10、网络编程
OSI七层模型是设计和描述网络通讯的基本框架,描述了网络硬件和软件若是以层的方式协同工做进行网络通讯。
(1)物理层
物理层并非指物理设备或屋里媒体,而是有关物理设备经过屋里媒体进行互联的描述和规定,物理层定义了接口的机械特性、电气特性、功能特性、规程特性等。
物理层以比特流的方式传送来自数据链路层的数据,不理会数据的格式和含义,它接收数据后直接传给数据链路层,物理层只能看到0和1.
(2) 数据链路层
数据链路层是OSI模型的第二层,负责从一台计算机到另外一台计算机无差错的传输数据帧,容许网络层经过网络链接进行虚拟的无差错传输。
一般,数据链路层发送一个数据帧后,等待接收方确认。接收方 数据链路层检测帧传输过程当中产生的任何问题,没有通过确认和损坏的帧都要进行重传。
(3) 网络层
负责信息地址和将逻辑地址与名字转换为物理地址。
网络层,数据传送的单位是包。网络层的任务是选择合适的路径和转发数据包,使发送方数据包可以正确的按照地址寻找到接收方的路径,并将数据包交给接收方。网络层负责最佳路径的选择。
网络层向传输成提供服务,同时将网络地址翻译成物理地址,还能协调发送、传输及接收设备能力不平衡的问题,网络层对数据进行分段和重组。
(4) 传输层
保证在不一样子网的两台设备之间数据包可靠、顺序、无差错的 传输。传输层数据传输的单位是段。传输层负责端到端通讯(一台计算机到另外一台计算机),中间能够有一个或多个交换节点。
传输层主要功能是将接收到的乱序数据包重新排序,并验证全部的分组是否已被接收到。
(5) 会话层
会话层是利用传输层提供的端到端的服务,向表示层或会话用户提供会话服务。会话层的功能是在两个节点间创建、维护和释放面向用户的连接,并对会话进行管理和控制,保证会话数据可靠传送。
会话链接和传输链接的三种关系:一对一关系,一个会话链接对应一个传输关系,一对多,一个会话链接对应多个传输关系;多对一关系,多个会话链接对应一个传输关系。
会话层协议有结构化查询语言SQL、远程进程呼叫RPC、Xwindows系统、AppleTalk会话协议、数字网络结构会话控制协议DNA SCP等。
(6) 表示层
表示层如下各层主要负责数据在网络传输时不会出错,可是数据传输没有错不表明数据所表示的信息没有错。表示层专门负责有关网络计算机信息表示方式问题。
(7) 应用层
直接与用户和应用程序打交道,负责对软件提供接口使程序能使用网络。应用层不仅为OSI模型外的其余应用程序提供服务。应用层协议:虚拟终端协议Telnet、简单邮件传输协议SMTP、简单网络管理协议SNMP、域名服务系统DNS、超文本传输协议HTTP。
TCP/IP协议族中最重要的协议是传输控制协议TCP、网络互连协议IP,TCP和IP负责管理和引导数据报在Internet上的传输,TCP负责和远程主机的链接,IP负责寻址,使报文被送到目的地。
(1) 网络接口层协议
TCP/IP网络接口层中包括各类无力层协议,如以太网、令牌环、帧中继、ISDN和分组交换网X.25。
(2) 网络层协议
网络层包括多个重要协议:有4个主要协议好比IP协议、ARP协议、RARP协议和ICMP协议。
IP协议:规定网际协议层数据报分组的格式。
ICMP因特网控制消息协议:提供网络控制和消息传递功能。
ARP地址解析协议:将逻辑地址解析成物理地址。
RARP反地址解析:经过RARP广播将物理地址解析成逻辑地址。
(3)传输层协议
主要有TCP和UDP协议,基于套接字的网络编程,是基于这两个协议实现的。
传输控制协议TCP:TCP是面向链接的协议,用三次握手和滑动窗口机制来保证传输的可靠性和进行流量控制。
用户数据报协议UDP:面向无链接不可靠的传输。
(1) 传输控制协议TCP
TCP和UDP最大区别是TCP是面向链接的,UDP是面向无链接的。
TCP协议采用许多机制保证端到端节点之间的可靠数据传输,如采用序列号、确认重传、滑动窗口等。
首先,TCP为所发送的每个报文段加上序列号,保证每个报文段能被接收方接收并只被正确的接收一次。
其次,TCP采用具备重传功能的积极确认技术做为可靠数据流传输服务的基础。确认指接收端在正确的接收到报文段以后向发送端返回一个确认(ACK)信息。发送方将每一个已发送的报文段备份在本身的发送缓冲区里,并且在收到相应的确认以前不会丢弃所保存的报文段的。“积极”指发送方在每个报文段发送完毕的同时启动一个定时器,假如定时器的定时期满而关于报文段的确认信息还没收到,则发送方任务该报文段已经丢失并主动重发。为了不因为网络延迟引发的迟到确认和重复确认,TCP在每一个确认信息中捎带一个报文段的序号,使接收方能正确的将报文段和确认联系起来。
最后,采用可变长的滑动窗口协议进行流量控制,防止因为发送端与接收端之间的不匹配而引发数据丢失。
(2)TCP 连接的创建
TCP连接的创建包括创建链接、数据传输和拆除链接3个过程。 TCP经过TCP端口提供连接服务,最后经过链接服务来接收好而发送数据。TCP链接的申请、打开、关闭必须遵照TCP协议的规定。TCP使用三次握手来创建链接,连接能够由任一一方发起,也能够同时发起。一台主机上的TCP软件主动发起链接请求,另外一台主机上的TCP软件只能被动的等待握手。
三次握手:
① 源主机A的TCP向目的主机B发出链接请求报文段,首部中的SYN(同步)标志位应置为1,表示想与目标主机B进行通讯,并发送一个同步序列号X(例 SEQ=100)进行同步,表示在后面数据传送时第一个数据字节的序列号是X+1(101).
② 目标主机B的TCP收到链接请求报文后,如赞成,则发回确认,在报文中将ACK位和SYN位置1.确认号为X+1,同时也为本身选择一个序列号Y。
③ 源主机A的TCP收到目标主机的确认后想目标主机B给出确认,其ACK置为1,确认号Y+1,而本身的序号为X+1。TCP标准规定,SYN置1的报文段要消耗掉一个序号。
连接创建,源主机A向主机B发送第一个数据报文段时,其序号让为X+1,由于前一个确认报文段并不消耗序号。
TCP链接创建后,能够发送数据,数据发送结束,须要关闭连接,链接的关闭必须由通讯双方共同完成。通讯的一方没有数据须要发送给对方时,能够使用FIN段向对方发送关闭链接请求。虽然不在发送数据,但不排斥在这个链接上继续接受数据,只有当通讯的对方也递交了关闭链接的请求后,TCP链接才彻底关闭。
(3) 用户数据报协议UDP
UDP在传送数据以前不须要创建链接,对方的传输层在收到UDP报文后,不须要给出确认信号。
UDP协议特色:在UDP传送前不须要创建链接,传输前发送方和接收方相互交换信息使双方同步;UDP不对收到的数据进行排序,UDP报文中没有关于数据顺序的信息(TCP的序号),并且报文不必定是顺序到达;UDP对接收到的数据报不发送确认信号,发送端不知道数据是否被正确接收,也不会重发数据;UDP比TCP传输快。
(4) 客户机/服务器模式(C/S模式)
要求每一个应用程序有两个部分组成:一个部分负责启动通讯,另外一个部分负责对它进行应答。
20.二、套接口编程
套接口是操做系统内核的一个数据结构,是网络中节点进行通讯的门户。网络编程也称为套接口编程。
套接口也就是网络进程的ID,网络通讯归根究竟是进程间的通讯。网络中,每个节点(计算机或路由器)都有一个网络地址即IP地址,两个进程通讯时,首先要肯定各自所在网络节点的网络地址,可是网络地址只能肯定所在的计算机,一台计算机上可能同时运行着多个进程,因此还须要端口号进一步肯定和哪一个进程通讯。一台计算机上,一个端口号一次只能分配给一个进程,进程和端口号是一一对应的。
网络地址和端口号信息放在一个结构体中,组成套接口的地址结构,大多数套接口函数都须要指向一个套接口地址结构的指针做为参数,以此来传递信息,每一个协议族都定义了本身的套接口地址结构,套接口地址结构以
sockaddr_开头。
套接口三种类型:流式套接口(TCP套接口 SOCK_STREAM)、数据报套接口(UDP套接口 SOCK_DGRAM)、原始套接口(SOCK_RAW)。
网络技术中,端口有2中意思:一是物理端口,二是逻辑意义上的端口,通常指TCP/IP 协议中的端口,范围从0~65535.端口分为两类:一类是固定通用的端口,数值为0~1024,另外一类是通常端口,用来随时分配给请求通讯的客户进程。
套接口的数据结构
在bind、connect等系统调用中,特定于协议的套接口地址结构指针都要强制转换成该通用的套接口地址结构指针,通用套接口数据接口在sys/socket.h 中,以下:
struct sockaddr
{
uint8_t sa_len;
sa_family_t sa_family;
char sa_data[14];
}
IPv4套接口地址数据结构:
IPv4套接口地址数据结构以socketaddr_in命名,在netinet/in.h中,以下:
struct socketaddr_in
{
uint8_t sin_len; // 数据长度成员,通常不设置
sa_family_t sin_fanmily ; // 套接口结构地址族,IPv4为AF_INET
in_port_t sin_port; // 16位端口号。
strtct in_addr sin_addr; // 32位的IP地址
unsigned char sin_zero[8]; // 未用
}
struct in_addr
{
in_addr_t s_addr; //32位的IP地址。
}
20.三、基本函数
(1) 字节排序函数
计算存储方式分为大端模式、小段模式。端口号和IP地址都是以网络字节顺序存储的,网络字节顺序使用的是大端模式。某个系统所用是本身顺序为主机字节序。主机字节序和网络字节序的排序函数:
#include <netinet/in.h>
uint32_t htonl(uint32_t hostlogn);
uint16_t htons(uint16_t hostshort);
返回的是网络字节。
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);
返回的是主机字节。
4个转换函数中,h表明host,n表明network,s表明short,l表明long。
(2) 字节操纵函数
套接口编程中,须要一块儿操纵结构体中的某几个字节,字节操纵函数以下:
#include <string.h>
void bzero(void *dest,size_t nbytes); // 从dest指定地址开始的n个字节设置为0
void bcopy(const void *src,void *dest,size_t nbytes); // 复制函数
int bcmp(const void *ptrl,const void *ptr2,size_t nbytes);
void memset(void *dest,int c,size_t len);
void memcpy(void *dest,const void *src,size_t nbytes);
int memcmp(const void *ptrl,const void *ptrl,size_t nytes);
以b打头的函数有系统提供,以mem开头的由ANSI C提供。
(3) IP地址转换函数
TCP/IP网络上,用的IP都是以‘.’隔开的十进制数表示,套接口的数据结构中用的是32位的网络字节顺序的二进制数值,转换函数以下:
#include <arpa/inet.h>
int inet_aton(const char *straddr,struct in_addr *addrptr);
返回:转换成功返回1,不成功返回0.
将点分十进制IP地址转换为网络字节序的32位二级制数值。输入的点分十进制放在参数straddr中,返回二进制数值放在addrptr中。
char *inet_ntoa(struct in_addr inaddr);
返回:若成功则返回点分十进制数串的指针,失败返回NULL。
调用结果做为函数的返回值返回给调用它的函数。
int_addr_t inet_addr(const char *straddr);
返回:成功返回32位二进制的网络字节序地址,出错返回INADDR_NONE。
(4) IP和域名的转换
#include <netdb.h>
struct hostent *gethostbyname(const char *hostname);
实现域名或主机名到IP地址的转换,hostname指向存放域名或主机名的字符。
struct hostent *gethostbyaddr(const char *addr,size_t len ,int family);
实现IP地址到主机名或域名的转换。addr指向一个含有地质结构(in_addr)的指针,len是结构大小,对于IPV4 是4,IPv6值为16.
返回:成功返回hosten指着,失败返回NULL,同时设置全局变量h_errno为相应的值。h_errno值以下:
HOST_NOT_FOND主机没找到,TRY_AGNAIN出错重试,NO_RECOVERY不可修复性错误,NO_DATA指定的名字有效但没有记录。
结构体struct hostent定义:
struct hostent
{
char *h_name ; // 主机的正式名称
char *h_aliases; // 主机的别名
int h_addrtype; // 主机的地址类型
int h_length; // 主机的地址长度
char **h_addr_list; // 主机的IP地址列表
}
20.三、TCP套接口编程
大体工做流程:
(1) 服务器用soket()函数创建一个套接口,用这个套接口完成通讯的监听及数据收发。
(2) 服务器用bind()函数来绑定一个端口号和IP地址,使套接口与指定的IP和端口相连。
(3) 服务器调用listen()函数,使服务器的这个端口和IP处于监听状态,等待网络中客户机的链接。
(4) 客户机用socket()函数创建一个套接口,设定远程IP和端口号
(5) 客户机用connect()函数链接远程计算机的端口
(6) 服务器调用accept()函数来接收远程计算机的链接请求,创建与客户机通讯链接。
(7) 创建链接后,客户机用write()函数(或send()函数)向socket中写入数据。也能够用read()函数(或recv()函数)读取服务器发来的数据。
(8) 服务器用(7)的函数来接收和发送数据。
(9) 完成通讯后,使用close()关闭socket链接。
建立套接口:
系统调用socket生成一个套接口描述符,函数以下:
#include <sys/types.h>
#include <sys/socket.h>
int socket(int family,int type,int protocol);
若成功返回套接口描述符,若失败返回-1.
参数family指明协议族,PF_UNIX(UNIX协议族)、PF_INET(IPv4协议)、PF_INET6(IPv6协议)、AF_ROUTE(路由套接口)等,type指明通讯字节流类型:SOCK_STAREAM(TCP方式)、SOCK_DGRAM(UDP方式)、SOCK_RAW(原始套接口)、SOCK_PACKET(支持数据链路访问)等,参数protocol可设置为0。
socket系统调用为套接口在sockfs文件系统中分配一个新的文件和dentry对象,并经过文件描述符把它们与调用进程联系起来,进程能够像访问一个文件同样访问套接口在sockfs中对应的文件。进程不能用open()来访问该文件。
绑定端口
socket函数创建一个套接口后,须要使用bind函数在这个套接口上绑定一个指定端口和IP地址,函数以下:
#include <sys/types.h>
#incldue <sys/socket.h>
int bind(int sockfd,const struct sockaddr *my_addr,socklen_t addrlen);
返回:成功返回0,失败返回-1.
参数sockfd表示已经创建的socket描述符,my_addr sockaddr类型的指针,addrlen 表示myaddr的长度。
等待监听函数
socket的端口一直处于等待状态,监听网络中全部的客户机,耐心等待某一个客户机的发送请求,若是有链接请求,端口就会接受这个链接,函数以下:
#include <sys/socket.h>
int listen(int sockfd,int backlog);
返回:成功返回0,失败返回-1
sockfd表示已经创建的套接口,backlog表示同时处理的最大链接请求数目。listen并未真正的创建链接,真正接受客户端链接的是accept();一般listen函数在socket() bind() 以后调用,而后调用accept();
listen 函数只适用于SOCK_STREAM SOCK_DGRAM的socket类型,若是socket为AF_INET,在backlog最大设为128.
接受链接函数
若是某个时刻有客户机请求,并非理解处理这个请求,而是将这个请求放入等待队列中,系统空闲时处理请求,函数accept() 以下:
#include <sys/types.h>
#include <sys/socket.h>
int accept(int sockfd,sturct sockaddr *addr,socklen_t *addrlen);
返回:成功返回新的套接口描述符,失败返回0.
参数sockfd表示层处于监听状态的socket,addr是一个sockaddr类型结构体类型指针,系统会把远程主机的信息保存到这个结构体,addrlen 表示sockaddr的内存长度。
当addr接受一个连接时,会返回一个新的sock描述符,之后的数据传输和读取经过新的sock编号来处理。
请求链接函数
所谓请求链接,指在客户机向服务器发送信息以前,须要先发送一个链接请求,请求与服务器创建TCP通讯链接,connect函数完成这项功能,函数以下:
#include <sys/types.h>
#include <sys/socket.h>
int connect(int sockfd,const struct sockaddr *serv_addr,int addrlen);
返回:成功返回0,失败返回-1.
参数sockfd表示已经创建的socket,serv_addr结构体来存储远程服务器的IP与端口信息,addrlen表示sockaddr结构体的长度。
connect函数将本地的socket链接到serv_addr指定的服务器IP与端口号上去。
数据发送函数
创建完套接口并链接到远程主机上之后,能够把信息发送到远程主机上,而对于远程主机发送来的信息,本地主机须要进行接收处理。
用connect函数链接到远程计算机后,能够用send函数将信息发送到对方的计算机,对方也能够用send函数将应答信息发送到本地计算机,send函数以下:
#include <sys/types.h>
#include <sys/socket.h>
int send(int sockfd,const void *msg,int len,unsigned int flags);
返回:成功返回已发送的字符数,失败返回-1.
flags通常设置为0.
数据接收函数recv以下:
#include <sys/types.h>
#include <sys.socket.h>
int recv(int sockfd,void *buf,int len ,unsinged int flags);
返回:成功返回接收到的字节数,失败返回-1.
(8) write与read函数
当socket链接创建之后,向这个socket中写入数据即表示想远程主机中传送数据,从socket中读数据则至关于从远程主机中接收数据。read和write函数在socket编程中和send recv函数功能相似。
#include <unistd.h>
ssize_t read(int fd,const char *buf);
ssize_t write(int fd,const char *buf,size_t count);
20.四、UDP套接口编程
UDP是一个无链接不可靠的传输层服务,域名服务系统DNS,网络文件系统NFS使用的是UDP链接。
TCP套接字必须先创建链接(客户端connect请求链接,服务器listen()和accept()),而UDP不须要创建链接,它在电泳socket生成一个套接字后,在服务器端用bind绑定一个端口和IP,而后服务器进程挂起与recvfrom()调用,等待某一个客户机的请求,客户机sendto()请求一样挂起与recvfrom()调用,等待并接受服务器应答信号,数据完成后客户端调用close()释放通讯链路。
数据发送函数sendto,至关于TCP链接中的send()或write函数,sendto函数以下:
int sendto(int sockfd,const void *msg,int len,unsigned int flags,struct sockaddr *toaddr,int *addrlen);
数据接收函数recvfrom至关于TCP中的read 或recv函数。以下:
#include <sys/socket.h>
int recvfrom(int sockfd,void *buf,int len,unsigned int flags,struct sockaddr *fromaddr,int *addrlen);
20、5 原始套接口
有三种套接字:SOCK_STREAM SOCK_DGRAM SOCK_RAW ,原始套接口只能有root权限的用户建立,原始套接字有以下特色:
① 使用原始的套接口能够读写ICMP(互联网控制消息协议)及ICMPv6分组。
② 原始套接字能够读写特殊的IP数据包,内核不处理这些数据包的IP协议字段,而出错的诊断将依靠协议字段的意义。
③ 利用原始套接字经过设置IP_HDRINCL套接口选项建造本身的IP头部。
原始套接口的建立
int sockfd;
sockfd=socket(AF_INET,SOCK_RAW,protocol);
TCP套接字和UDP套接口的protocol为0,原始套接字的protocol取指能够是IPPROTO_ICMP IPPROTO_TCP IPPROTO_UDP等,不一样类型协议建立不一样的原始套接字。
二11、图形界面编程
图形用户界面(Graphical user interface)简称GUI,是指采用图形的方式显示的计算机操做用户界面。GUI的组成部分包括桌面、视窗、单一文件界面、多文件界面、标签、菜单、图表、按钮等。用来进行图形用户界面编程的工具(库)成为GUI工具包(GUI库),GUI库是构造图形界面所使用的一套按钮、滚动条、菜单和其余对象集合。可供使用的GUI库,如Motif、Qt、GTK+等,最经常使用的是GTK+ 和Qt。
21.一、窗口
窗口是一个应用程序的框架,程序的全部内容与用户的交互都在这个窗口中,设置应用程序界面时第一步是创建一个窗口。gtk_window_new()函数创建一个GTK+窗口,函数以下:
#include <gtk/gtk.h>
GtkWidget *gtk_window_new(Gtk WindowType type);
返回:若成功,返回一个GTKWidget类型的指针,失败返回空指针NULL。参数type表示一个窗口状态常量,可能的取值如下两种:
GTK_WINDOW_TOPLEVEL:表示这个窗口是一个正常的窗口。窗口能够最小化,在窗口管理中能够看到这一窗口按钮。窗口控制器至关于windows下的任务栏。
GTK_WINDOW_POPUP: 表示这个窗口是一个弹出式窗口,不能够最小化。但这个窗口是一个独立运行的程序,并非一个对话框。
gtk_window_new()函数的返回值是一个GtkWidget类型的指针,图形界面的全部元素都会返回这个指针。GTKWidget结构体的定义:
typedef struct
{
GtkStyle *style; // 元件的风格
GtkRequisition requisition; // 元件的位置
GtkAllocation allocation; // 容许使用的空间
GtkWindow *window; // 元件所在的窗口或父窗口
GtkWidget *parent; // 元件的父窗口
}GtkWidget;
新建一个窗口之后,这个窗口不会立刻显示出来,须要调用窗口显示函数gtk_window_show()来显示这个窗口,函数以下:
#include <gtk/gtk.h>
void gtk_window_show(GtkWidget *widget);
参数widget是一个GtkWidget类型的结构体指针,指向须要显示的窗口。
设置窗口标题gtk_widnow_set_title()函数以下:
#include <gtk/gtk.h>
void gtk_window_set_title();
指针title所指向的字符串必须是英文字符的,但若是咱们想要显示中文字符,使用g_locale_to_utf8()函数进行批注。
设置窗口的大小和位置
窗口的大小指的是窗口的宽度和高度,用gtk_widget_set_usize() 函数来设置一个窗口的初始大小。窗口的位置指的是窗口的左上角顶点到屏幕左边和顶边的距离,能够用gtk_widget_set_uposition()函数来设置一个窗口的初始位置,函数下:
include <gtk/gtk.h>
void gtk_widget_set_usize(GtkWidget *widget,gint width,gint height);
void gtk_widget_set_position(GtkWidget *widget ,gint x,gin y);
标签:
标签是程序中的一个文本,这个文本能够显示必定的信息,用户不能输入和改变标签内容,界面中的提示信息和显示内容都是经过标签来实现的。
新建一个标签:
使用标签以前,须要新建一个标签,gtk_lable_new() 用来新建一个标签,函数:
#include <gtk/gtk.h>
GtkWidget * gtk_lable_new(gchar *text);
返回:成功则返回一个GtkWidget的指针,若失败则返回NULL。
参数text表示要显示的内容,和窗体同样,新建标签后须要调用显示函数gtk_widget_show()来显示这个标签,函数以下:
#include <gtk/gtk.h>
void gtk_widget_show(GtkWidget *lable);
参数label表示gtk_lable_new()新建的标签,无返回值
将标签添加到窗口:
GTK+窗口中,除了window窗口外,其余的原件都必须放在一个容器中,例如新建的标签不能直接显示,须要放在一个容器中。gtk_container_add()函数的做用就是把一个元件放置在一个容器中,函数以下:
#include <gtk/gtk.h>
void gtk_container_add(GtkContaner *contaner,GtkWidget *widget);
container是一个父级的容器指针,widget是须要放置元件的指针。无返回值。
gkt_table_add()能够将一个标签添加到一个表格中,而后用gtk_container_add()将表格添加到窗口中。
设置和获取标签的文本
用gkt_lable_get_text()函数来获取一个标签的文本,使用gtk_lable_set_text()函数来设置一个标签的文本,函数以下:
#include <gtk/gtk.h>
const char *gkt_lable_get_text(GtkLable *lable); 返回:成功返回标签文本的字符串指针,失败NULL
void gtk_lable_set_text(GtkLable *lable,gchar *text); 无返回值
lable 是一个指向标签的指针,text表示标签须要设置文本。
按钮:
新建一个按钮,函数:
GtkWidget * gtk_button_new(gchar *lable);
返回:若成功,返回一个GtkWidget 指针,失败返回NULL。
新建成功后,调用gtk_widget_show()来显示这个按钮。
设置和获取按钮的标签:
按钮的标签指的是按钮上的文字,gtk_button_get_lable()获取某个按钮的标签,函数gtk_button_set_lable();设置某个按钮的标签,函数以下:
#include <gtk/gtk.h>
const char *gtk_button_get_lable(GtkButton *button);
void gkt_button_set_lable(GtkButton *button ,const gchar *lable);
button指向按钮的指针,lable ,按钮标签的内容。按钮一般伴随着一个事件。
文本框:
gtk_entry_new();函数来新建一个文本框,以下
GtkWidget * gtk_entry_new(void);
GtkWidget *gkt_entry_new_with_max_length(gint max);
两个函数的做用同样,max表示最多输入的字符个数。
设置和获取文本框内容
#include <gtk/gtk.h>
const char *gtk_entry_get_text(GtkEntry *entry);
void gtk_entry_set_text(GtkEntry entry ,const gchar *text);
GTK 是用utf8显示的,所显示的字符都须要utf8才能正常显示,使用g_local_to_utf();函数来转换,能够使用中文。本地字符和utf8字符的转换函数:
gchar * g_local_to_utf8(gchar *string,gssize len,gsize *bytes_read,gsize *bytes_written,GError **error);
gchar * g_local_from_utf8(gchar *string,gssize len,gsize *bytes_read,gsize *bytes_written,GError **error);
21.二、界面布局元件
界面布局元件包括表格、框、窗格等。表格是界面中最经常使用的元件,经过在单元格中插入不一样元件来实现布局和排列。若是一个元件中能够放其余的元件,这个元件叫容器。
表格的创建,函数以下:
#include <gtk/gtk.h>
GtkWidget *gtk_table_new(guint rows,guint columns,gboolean homogeneous);
参数rows表示行数,columns表示列数,homogeneous是一个布尔值,若是设置为TURE则每一个单元格大小相同,若是设置为FALSE则表格的大小会根据单元格中元件的大小自动调整。表格并不真正显示,只是容纳其余元件和布局用的。
将其余元件添加到表格中,函数以下:
#include <gtk/gtk.h>
void gtk_table_attach(GtkTable *table ,GtkWidget *child,guint left_attach,guint right_attach,guint top_attach,guint bottom_attach,GtkAttachOptions xoption,GtkAttachOptions yoptions,guint xpadding,guint ypadding);
参数xoptions和yoptions 分别表示元件在表格中的 水平方向和垂直方向对其方式,xpadding,ypadding 分别表示元件与边框水平方向和垂直方向的边距。
GtkOptions的取值有三个:GTK_EXPAND元件以设置的大小显示,若是大于容器的大小则容器自动变大,GTK_SHRINK 若是元件大于容器的大小,则自动缩小元件,GTK_FILL元件填充整个单元格。
嵌套表格:
设计复杂界面时,须要在一个表格中添加表格,实现表格嵌套,表格也是一个普通元件,能够把一个表格添加到另外一个表格的单元格中。
22.三、信号与回调函数
图形界面的程序是事件驱动的程序,程序进入gtk_main()函数后,等待事件的发生,一旦发生某个事件,相应的信号将产生,若是程序中定义了相应的消息处理函数(回调函数),系统会自动进行调用。
信号的做用是对某一个元件添加一个用户交互的功能,g_signal_connect() 能够把一个信号处理函数(回调函数)添加到一个元件上,在元件和处理函数间创建关联,函数以下:
gulong g_signal_connect(GtkObject *object,gchar *name,Gcallback callback_func,gpointer func_data);
参数object是一个元件的指针,指向将产生信号的元件。name表示消息或时间的类型,一个按钮的全部事件类型:activate 激活的时候发生,clicked 单击之后发生,enter 鼠标指针进入这个按钮之后发生,leave 鼠标离开这个按钮之后发生,pressed 鼠标按下之后发生,released 鼠标释放之后发生。
参数callback_func表示信号产生后将要执行的回调函数,func_data 传递给回调函数的数据。
函数的返回值用于区分一个元件的一个事件对应的多个回调函数,一个元件上能够有不少个事件好比按钮的单击和双机,每一个事件能够有0个或多个处理函数。
(2) 回调函数
消息处理函数(回调函数)原型:
#include <gtk/gtk.h>
void callback_func(GtkWidget *gtkwidget,gpointer func_data);
参数gtkwidget指向要接收消息的元件,func_data指向消息产生时传递给该函数的数据。
附件:我遇到的问题及解决办法(若是错误,深刻学习后再来修改)
一、安装CH340驱动(源码)
(1) 下载了CH340驱动的压缩包.zip格式
(2) 用U盘拷贝到虚拟机的home目录。
(3) unzip filename.zip 解压缩文件,文件中包含了.c 文件 和makefile
(4) make 命令进行编译
(5) apt install sl 命令进行安装
源码的安装方式:
(1) 下载源码包,根据压缩包的类型使用相应的命令进行解压缩
(2) 进入解压缩后的目录 执行 ./configure 命令检查安装环境(库函数、头文件),能够指定安装目录,若是不指定默认在当前目录。
(3) make 生成makefile 文件
(4) make install 进行安装。
二、minicom安装
ubuntu使用命令sudo apt-get install minicom 进行安装,也能够从光盘镜像或者源码安装。
第一次配置使用root用户权限使用命令:minicom -s 而后就能够配置,配置完成后保存,在etc目录下就有了minicom文件夹保存配置。
三、能够用ls -l 或者ll 命令来查看目录下各个文件的类型及读写执行权限,d开头的是目录文件,l开头的是连接文件,_开头的是普通文件,b开头的是块设备,c开头的是字符设备。浅蓝色的是目录,绿色的是可执行文件。
chmod命令能够改变目录或文件的权限,好比chmod 755 a.txt 755分别表示拥有者、组、其余用户的权限,值按照r、w、x顺序,容许就为1,不容许为0,好比rwxr-xr--权限就是754.
bin文件夹存放的是二进制文件,主要是用户命令。
lib文件夹存放的是动态的连接库。
(2)能够去/sys/bus/usb-serial/drivers/ 查看USB转串口设备以及设备号
四、shell的环境变量,PATH、HOME、HOSTNAME、LOGNAME、"echo $环境变量"显示环境变量的信息。
临时变量(自定义变量)使用export变成环境变量。
export PATH=/home/yang :$PATH ,添加环境变量并保持原来的,用来加载除了/lib和/usr/lib之外的其余连接库。
$引用变量。
五、Ubuntu 创建的sh文件,执行时不少状况下须要修改文件的权限。
六、 .tar.xz 压缩包的安装
解压安装包: tar -vxf xxx.tar.gz
进入解压后的包: cd xxx
配置编译环境:./configure
进行编译:make
安装软件:make install
七、Ubuntu下GTK+环境的安装
先去/usr/include 目录下看看有没有gtk-2.0
安装依赖关系:sudo apt-get install build-essential libgtk2.0-dev
编译文件: gcc -o xxx -c xxx.c `pkg-config --cflags --libs gtk+-2.0`
注意:
.c文件的执行须要包括pkg的配置命令,不然会提示找不到gtk.h
符号“`” 上斜点的位置做在键盘esc键下边 带~号的键。