Unix实践编程入门笔记Word文档格式.docx
《Unix实践编程入门笔记Word文档格式.docx》由会员分享,可在线阅读,更多相关《Unix实践编程入门笔记Word文档格式.docx(50页珍藏版)》请在冰豆网上搜索。
▪对当前记录做修改
▪关闭文件
▪处理系统调用中的错误
▪错误种类errno在errno.h中或man3error
▪
▪不同错误需要不同处理
▪perror显示出错信息
▪perror("
Cannotopenfile"
)
第三章目录与文件属性
▪磁盘上的文件和目录被组成一个目录树,每个节点都是目录或文件
▪每个文件都位于某个目录中,在逻辑上没有驱动器或者卷
▪目录
▪一种特殊的文件类似utmp文件
▪是文件的列表,是记录的序列,每条记录对应一个文件或子目录
▪通过readdir来读取目录中的当前记录的指针记录类型为structdirent
▪opendir打开一个目录
▪readdir返回目录中的当前项
▪closedir关闭一个目录
▪字段编码
▪把多种信息编码到一个整数的不同字段中是一种常用技术
▪掩码
▪为了比较,把不需要的地方置零,这种技术叫做掩码masking
▪将用户/组ID转换成字符串
▪/etc/passwd包含用户列表
▪/etc/passwd并没有包括所有的用户
▪/etc/group是组的列表
▪UID没有对应的用户名
▪用户可以同时属于多个组
▪通过getpwuid来得到完整的用户列表
▪通过getgrgid来访问组列表
▪stat
▪st_mode成员包含16位,其中四位用作文件类型,9位用作许可权限,剩下的三位用作文件特殊属性.
▪三位中的第一位叫做set-user-ID
▪SUID经常用来给某些程序提供额外的权限
▪可以通过sys/stat.h定义的掩码来检验一个程序是否有SUID位
▪第二位是set-group-ID
▪修改文件的权限
▪文件类型
▪普通文件,目录文件,socket文件,符号链接文件,命名管道文件
▪文件一旦建立,类型就无法修改
▪chown更改文件的用户
▪chown("
file"
200,20);
▪将用户ID改为200,将组ID改为40
▪chgrp修改文件的所有组
▪文件大小
▪可以用creat将文件大小置0
▪时间
▪每个文件都有3个时间
▪最后修改时间,最后访问时间和属性最后修改时间
▪utime系统调用可以用来设置最后修改时间和最后访问时间
▪shell命令touch也可修改文件的最后访问时间和最后修改时间
▪文件名
▪修改文件名
▪create(char*old,char*new)
第四章文件系统
∙文件操作命令
olnxx-link
▪x-link指向x
oln命令的作用是生成一个链接
▪链接是指向文件的一个指针,表明,x-link和x都指向硬盘上的统一数据块
ols>
x-ling将ls的输出作为文件x-link的内容
∙目录树的命令
ols-R列出指定目录以及其子目录的所有内容
∙目录树的深度几乎没有限制
∙Unix文件系统的内部结构
o第一层从磁盘到分区
o第二层从磁盘到块序列
o第三层,从块序列到三个区域的划分
∙unix将磁盘块分成三个部分任何一部分都由很多有序的磁盘块组成,文件系统就是由这三部分组成
o超级块
▪文件系统中的第一块,被称为超级块,存放文件系统本身的结构信息
oi-节点表
▪每个文件的属性被记录在i-节点的结构中,所有节点具有相同的大小
▪每个节点都通过位置来标识,例如标识为2的节点位于第三个位置
o数据块
▪保存文件的内容
∙创建一个文件的过程
o存储属性
▪找到一个空的i-节点,内核将文件的信息记录在其中
o存储数据
▪在内核中自由块中招出3个自由块
o记录分配情况
▪文件内容按顺序存放在自由块中,内核在i-节点的磁盘分布区记录了上述的自由块序列,
o添加文件名到目录
▪内核将接口添加到目录文件(节点,filename)
∙文件系统的实现:
目录的工作过程
o可以通过ls-1iademodir来查看目录的内容,输出的为文件名对应的i节点号
ols-i查看一个文件的i节点号
o对open的每次调用都是先查找文件名,然后得到节点号,通过节点号再得到文件属性最终找到文件内容
o存在间接块:
存放的是更多磁盘块
∙使用ls-iaR可以列出一棵树中的所有文件的i节点号
∙如果目录中有两个连接的状态完全相同,它们称为指向文件的硬链接.内核记录了一个文件的链接数.
∙mv仅仅是调用了系统命令rename
orename:
复制链接至新的名字/位置,删除原来的链接
∙cd调用了系统函数chdir
ochdir改变进程的当前目录,进程有一个存放当前目录节点好的变量,从一个目录进入两一个目录只是改变那个变量的值
∙link和rename不可以创建跨域设备的链接和拒绝在不同的文件系统间进行节点号的转移.
∙df-i命令查看各分区inode情况
∙df-h可以查看各个分区的使用情况
第五章连接控制:
学习sty
∙设备就像文件:
ounix中各种声卡,终端,鼠标和磁盘文件是同一种对象.每个设备都有一个文件名,一个i节点号,一个文件所有者,一个权限位的集合和最近修改时间
o
∙
设备文件的属性
o设备文件和文件大小
▪设备文件是链接而不是容器,不存储击键数和点击数.
▪设备文件的i节点存储的是指向内核的程序的指针,而不是文件大小和存储列表
▪运行ls/dev/pts/0-al
▪输出在文件大小位置的两个数字136,0前者是主设备号,后者是从设备号
▪主设备号:
确定除了该设备实际的子程序
▪从设备号:
作为参数传输到该子程序
o设备文件和权限位
▪只有文件的所有者有读的权限,二同一组的tty成员拥有写设备的权限
o设备文件和i节点
▪文件类型的区别体现在i-节点上
▪i节点可以是磁盘文件,也可以是设备文件,i节点的类型被记录在结果stat的成员变量st_mode类型区域中
▪read在i节点先获取其类型,如果是磁盘文件则通过分配表来读取数据,如果是设备文件,则调用该设备驱动程序的read部分来读取数据
∙设备与文件的不同
o磁盘链接具有缓冲这样一个属性.到终端的链接则不同,进程需要尽快把终端的数据传送出去
∙硬盘链接的属性
o缓冲
▪通过修改控制变量改变文件描述符的动作
▪例关闭磁盘缓冲
▪生成一个系统调用,将控制变量从文件描述符复制到进程
▪修改这个复制过来的控制变量
▪将新的设置安置到进程代码中
o自动添加模式
▪为了避免同时对一个文件描述符写入出现的竞争现象
▪当O_APPEND被置位,lseek和write组合成一个原子操作,即不可分割
▪s=fcntl(fd,F_GETEL);
▪s|=O_APPEND;
▪result
=fcntl(fd,F_SETFL,s);
▪write(fd,&
rec,1);
∙终端连接的属性
o终端驱动程序
▪终端和进程之间由终端驱动器连接,处理进程和外部设备间数据流的内核子程序被称为终端驱动程序,或者tty驱动程序
ostty命令
▪可以让用户读取和修改tty的设置
ostty关于设置
▪输入:
▪输出:
▪控制:
字符如何表示位的个数,位的奇偶性
▪本地:
如何处理来自驱动程序内部的字符
第六章终端控制和信号
∙软件工具与针对特定设备编写的程序
o对磁盘文件和设备文件不加以区分的程序被称为软件工具
o事实上大多数进程自动将前三个文件描述符打开,它们不需要调用open()来建立连接
o用户程序的常用设置
▪立即响应击键事件
▪有限的输入集
▪输入的超时
▪屏蔽ctrl-c
∙终端驱动程序的模式
o规范模式
▪缓冲和编辑包含规范处理
▪例如回显,缓冲,编辑,控制处理
o非规范模式
▪stty-icanon
▪关闭回显,关闭缓冲这样输入什么字符后,将直接传递给用户程序
oraw模式
∙阻塞与非阻塞输入
o当调用getchar或read从文件描述符读取输入时,这些调用会等待输入
o阻塞不仅仅是终端连接的属性,而是任何一个打开的文件的属性
▪程序可以通过fcntl或open为文件描述符启动非阻塞输入
▪阻塞模式是必须等一个阻塞条件解除后进程才能继续执行.
▪非阻塞模式是不管条件满不满足都不停地执行下去
∙信号
oCtrl-C做了什么
▪用户输入C-c
▪驱动程序收到字符
▪匹配VINTR和ISIG的字符被开启
▪驱动程序调用信号系统
▪信号系统发送SIGINT给进程
▪进程收到SIGINT
▪进程消亡
o每个信号都有一个数字编码,中断信号通常是编码2
o信号来源
▪用户
▪发送C-c或者其他分配给信号控制字符
▪内核
▪当进程出错,内核给进程发送一个信号,如非法段存取,浮点数溢出
▪进程
▪一个进程可以和两一个进程通过信号通信
o进程如何处理信号
▪默认处理,通常消亡
▪忽略信号
▪调用一个函数
▪signal(intsignum,void(*action)(int))
▪action可以是函数名和SIG_IGN忽略信号和SIG_DFL将信号恢复为默认处理两个之一
▪在出程序装载了signal()函数后,如果进程遇到对应的signal,将会进入到对应的处理函数,然后再跳转到前一个位置,就像子过程调用
o进程终止
▪unix有两个信号是不能被忽略和捕捉的
第七章事件驱动编程:
编写一个vedio游戏
∙sleep
olinux中的sleep(n)函数是将当前进程挂起n秒,或者在此期间被一个不能忽略的信号的到达所唤醒
osleep是如何工作的
▪设置闹钟的秒数
▪睡觉直到闹钟响起
o系统中每一个进程都有一个私有的闹钟,时间一到,时钟就发送一个信号SIGALARM给进程
osleep函数
▪为SIGALRM设置一个处理函数
▪调用alarm(num_seconds);
▪调用pause,动用pause挂起进程直到信号到达,任何信号都可以唤醒进程,而非仅仅等待SIGALRM
∙间隔计时器
o每个进程有3个独立的计时器,每个计时器都有两个设置:
初始间隔和重复间隔.
∙添加精度更高的时延usleep
ousleep(n)将进程挂起n微秒,直到一个不能忽略的信号到达
∙三种计时器
oITIMER_REAL
▪不管程序在用户态还是核心态,计时器都会及时,当计时器用尽,发送SIGALRM信息
oITIMER_VIRTUAL
▪只记录用户态的运行时间,计时器用尽发送SIGVTALRM消息
oITIMER_PROF
▪
这个计时器在进程运行于用户态或由该进程调用而陷入核心态时计时.当这个计时器用尽发送SIGPROF
∙两种间隔
o初始和重复
▪每个间隔计时器的设置都有这样两个参数:
初始时间和重复间隔
▪it_value和it_interval
▪如果不需要重复将interval设置为0
▪把两个时钟都关掉的话value设置为0
o通过设置structitimerval中的值然后将这个结构体通过调用setitimer传给计时器,读取计时器的设置用getitimer
∙计算机有几个时钟
o每当内核收到系统时钟脉冲,它遍历所有的间隔计时器,使每个计数器减一个时钟单位,如果进程A的计数器达到0的时候,内核发送SIGALRM给进程A.如果进程A已经设置了计时器的it_interval值,内核将这个值复制到it_value计数器.否则关掉这个计数器
∙信号处理:
使用signal
oPOSIXUnix型可移植操作系统接口的信号处理模型
o处理多个信号
▪捕鼠器,当信号或老鼠被捕获,信号处理函数或捕鼠器就失效,再每次捕获后需要重新设置
▪不可靠的信号
▪两个sigints杀死进程
▪sigy打断sigx的处理函数
▪sigx打断sigx的处理函数
▪递归调用同一个处理函数
▪忽略第二个信号
▪阻塞第二个信号直到第一个处理完毕
▪被中断系统调用
o信号机制其他弱点
▪不知道信号被发送的原因,只知道是什么类型的信号
▪处理函数中不能安全的阻塞其他消息
∙处理多个信号sigaction
o#include<
stdio.h>
signal.h>
unistd.h>
ointi=0;
ointmain(intargc,constchar*argv[])
o{
o
structsigactionnewhandler;
sigset_tblocked;
voidinthandler();
charx[128];
newhandler.sa_handler=inthandler;
newhandler.sa_flags=SA_RESTART;
sigemptyset(&
blocked);
sigaddset(&
blocked,SIGQUIT);
newhandler.sa_mask=blocked;
if(sigaction(SIGINT,&
newhandler,NULL)==-1)
perror("
sigactiondown"
);
else{
while
(1){
fgets(x,128,stdin);
printf("
input:
%s\n"
x);
}
return0;
o}
ovoidinthandler()
++i;
intx=i;
Calledwithsignal%d\n"
sleep(x);
okthissignal%ddone\n"
∙防止数据损毁
o临界区
▪一段修改一个数据结构的代码如果在运行时被打断,将导致数据的不完整或损毁,这段代码称为临界区
▪在程序处理信号的时候必须决定那一段代码是临界区并设法保护
▪保护临界区的简单方法就是阻塞和忽略将要使用或修改特定数据的信号
o阻塞信号sigprocmask和sigsetops
▪处理一个信号阻塞另一个要设置sa_mask位是sigset_t类型定义了一个信号集
▪信号挡板
▪任何时候一个进程都有一些信号被阻塞,这个信号集就是信号挡板
▪sigprocmask可以修改这个信号集
▪sigprocmask(inthow,sonstsigset_t*sigs,sigset_t*prev);
▪how如何修改信号挡板,依次是添加,删除和替换
▪SIG_BLOCK
▪SIG_UNBLOCK
▪SIG_SET
▪sigs指向信号列表的指针
▪prev指向之前的信号挡板的指针或者是null
▪用sigsetops构造信号集
▪sigemptyset(sigset_t*setp)清除setp指向的所有信号
▪sigfillset(sigset_t*setp)添加所有信号到setp指向的列表
▪sigaddset(sigset_t*setp,intsignum)添加signum到setp指向的列表
▪释放资源时恢复获取时的状态是个好习惯
o重入代码
▪可重入
▪如果一个函数或者信号处理在激活状态下能被调用并且不引起任何问题就称之为可重入的
▪在sigaction设置时设置为SA_NODEFER来允许函数递归调用,反之清除此位来阻塞信号
▪如果处理不可重入则必须阻塞信号,如果阻塞则有可能丢失信号
okill:
从另一个进程发送信号
▪一个进程可以通过kill系统调用向另一个进程发送信号
▪intkill(pid_tpid,intsig)
▪pid目标进程pid
▪sig要被发送的信号
▪返回值:
-1失败,0成功
∙输入信号:
异步IO
o硬件实现
第八章编写sh学习进程
∙ps就是运行中的程序
oWCHAN程序休眠的原因
∙进程管理与文件管理
o文件包含数据
o进程包含可执行代码
∙内存和程序
o内存可看做由页面构成的数组,将进程分割到不同的页面
o一个进程不一定必须占用连续的内存
o内核要找到一些用来存放程序指令和数据的空闲内存页,内核还要建立数据结构来存放相应的内存分配情况和进程属性
∙shell的功能
oshell进程控制和程序控制的一个工具
o运行程序
▪shell将应用程序载入内存并运行,程序启动器
o管理输入和输出
▪shell可以用<
>
|来将输入输出重定向,这样就可以告诉shell将进程的输入输出连接到一个文件或是其他的进程
o编程
▪shell带有变量和流程控制的编程语言
∙shell如何运行程序
o用户键入a.out
oshell建立一个新的进程来运行这个程序
oshell将程序从磁盘载入
o程序在它的进程中运行直到结束
o即学会
o运行一个程序
o建立一个进程
o等待exit()
∙一个程序如何调用另一个程序
oexecvp("
progname"
arglist)将指定的程序复制到调用它的进程
oexc系统调用从当前进程中把当前程序的机器指令删除,然后在空的进程中载入调用指定的程序代码,最后运行这个新的程序,exec调整进程的内存分配,相同进程,不同内容
∙如何建立新的进程
o一个进程调用fork来复制自己
▪分配新的内存块和内核数据结构
▪复制原来的进程到新的进程
▪向运行进程集添加新的继承
▪将控制返回给两个进程
o新的进程从fork返回的地方开始运行
ofork()在子进程中返回的是0,在父进程返回子进程的进程号
∙父进程如何等待子进程退出
o进程调用wait等待子进程结束
o解释wait()
▪wait挂起调用它的进程直到得到这个进程的子进程的一个结束状态,wait返回结束进程的pid,如果调用的进程没有子进程也没有得到终止状态值,wait返回-1
▪wait暂停调用它的进程直到子进程结束,然后wait取得子进程结束时传给exit的值
▪最终子进程会结束任务并调用exit(n)n是0-255的一个数字
▪intstatus
▪wait(&
status),最终status的值就是exit(n)中的n
o例
▪pid=fork()
▪switch(pid):
▪case-1:
forkfailed!
"
▪exit(-1);
▪case0:
//说明是子进程
▪execvp("
ls"
arglist);
execvpfailed!
)//如果运行无误的话子进程是运行不到此部分的
▪default:
▪while(wait(NULL)!
=pid);
o退出主进程的办法只能是ctrl-c但是如果在子进程等待的时候按了ctrl-c则会将两个进程全部杀死
o因为键盘信号发给所有连接的进程,可以通过之前学习的知识装填相应的信号处理函数对相应进程收到的信号进行处理
ounix提供方法来建立全局变量.即是利用环境
∙exit和exec的其他细节
o那些已经死亡但是没有exit赋值的进程为僵尸进程,ps会将其列为defunct
o系统调用_exit()
▪关闭所有的文件描述符和目录描述符
▪将PID置为init进程的PID
▪如果父进程调用wait或者waitpid来等待子进程结束,则通知父进程
▪向父进程发送SIGCHLD
▪如果子进程的父进程退出了,子进程也会继续运行,并成为init进程的子进程
∙exec家族
oexecl()
l是list的意思
▪execl(fullname,arg0,arg1,...);
oexeclp()p是path的意思会在环境变量PATH中来找第一个参数指定的程序
▪execlp(filename,arg0,arg1,...);
第九章可编程的shellshell变量和环境
∙shell的编程特征
o变量,I/O和i