博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
unix高级环境编程-读书笔记(1)
阅读量:5899 次
发布时间:2019-06-19

本文共 3753 字,大约阅读时间需要 12 分钟。

在研读了鸟哥的linux私房菜之后,对linux有了大致的概念,下面就开始研读linux学习中被称为圣经的:《Advanced Programming in unix environment》,也就是众所周知的unix环境高级编程。

unix体系结构:

操作系统实际上是一个软件,也就是内核,而内核的接口被称为系统调用(system call),公用函数库构建在系统调用接口之上,应用程序既可调用函数库,也可使用系统调用。

登陆shell:

shell 是一个命令解释器,读取用户输入,然后执行命令,用户有时通过终端shell,有时通过文件(shell脚本)向shell进行输入,常见的shell如下所示

文件和目录:

unix文件系统是目录和文件组成的一种层次结构,当创建新目录时会自动创建两个文件名,   .和.. ,其中点指向当前目录,点点指向父目录,在最高层次的根目录中,.和..没有区别。

ls的c语言编程实现

准备工作:linux下c的头文件都放在/usr/include目录下,在unix这本书中,有很多源代码,但里面都包含了一个头文件apue.h,是作者自己写的,linux并不包含这个,因此需要在官网下载这个头文件,并放在/usr/include下,官网:http://www.apuebook.com/。并且要在apue.h的最后一行,也就是#endif之前一行,加上#include "error.c"。然后将下载的源代码中..apue.2e/lib目录下找到error.c这个文件,放到/usr/include目录下即可。

源代码:

#include"apue.h"#include 
int main( int argc , char *argv[]) //将命令行的第一个参数argv[1]作为目录名。 { DIR *dp; struct dirent *dirp; if(argc !=2) //当命令行参数不等于2,也就是没有写要列出的目录时,会报错 err_quit("usage: ls directory_name"); if((dp =opendir(argv[1]))==NULL) //调用opendir函数,返回指向dir结构的指针,当返回值dp是null,表明不存在这个目录 err_sys("can't open %s",argv[1]); while ((dirp = readdir(dp)) !=NULL) //将这个dp指针传递给readdir,这里用到while循环结构,一直到readdir函数无目录可读返回null时,结束程序。 printf("%s\n",dirp->d_name); closedir(dp); exit(0); //程序结束,以参数0调用exit函数,表示正常结束,参数值1-255表示出错。 }

编译好后,默认名是a.out

也就是./a.out 相当于ls命令

比如

程序和进程:

unix确保每一个进程都有一个唯一的数字标识符,称为进程ID,进程ID总是一非负数。

源代码:打印进程ID

#include "apue.h"intmain(void){	printf("heollo world from process ID %d\n",getgid());  //调用getgid函数来调用进程ID	exit(0);}

getpid返回一个pid_t数据类型,我们不知道其大小,仅知道的是标准会保证它能保存在一个长整型中。

进程控制:

有三个用于进程控制的主要函数:fork、exec和waitpid

源代码:从标准输入命令并执行

#include "apue.h"#include 
int main(){ char buf[MAXLINE]; pid_t pid; int status; printf("%% "); while (fgets(buf,MAXLINE,stdin)!=NULL) //标准fgets从标准输入一次读一行,当输入文件结束字符(ctrl+d)作为行的第一个字符 //,fgets返回一个null,循环终止,退出进程 {, if(buf[strlen(buf) -1]=='\n') //用null代替换行符,因为execlp函数要求参数以null结束 buf[strlen(buf) -1]=0; if((pid=fork())<0) //调用fork创建一个新进程,这个新进程称为子进程,fork向父进程返回子进程的ID(非负),对子进程返回0 { err_sys("fork error"); } else if(pid == 0) //子进程 { execlp(buf,buf,(char *)0); //在子进程中,调用execlp以执行从标准输入读入的命令, err_ret("couldn't execute: %s",buf); exit(127); } if((pid = waitpid(pid, &status,0))<0) // 父进程等待子进程结束,waitpid返回子进程的终止状态, err_sys("waitpid error"); printf("%% "); } exit(0);}

这个程序利用标准IO函数fgets从标准输入一次读一行,execlp函数执行新程序文件。

int execlp(const char * file,const char * arg,....);

execlp()会从PATH 环境变量所指的目录中查找符合参数file的文件名,找到后便执行该文件,然后将第二个以后的参数当做该文件的argv[0]、argv[1]……,最后一个参数必须用空指针NULL)作结束。如果用常数0来表示一个空指针,则必须将它强制转换为一个字符指针,否则将它解释为整形参数,如果一个整形数的长度与char * 的长度不同,那么exec函数的实际参数就将出错。如果函数调用成功,进程自己的执行代码就会变成加载程序的代码,execlp()后边的代码也就不会执行了。

该程序的主要限制就是不能向所执行的命令传递参数,例如不能指定要列出目录项的目录名,只能对工作目录执行ls命令。如果要传递参数,先要分析输入行,然后用某种约定将参数分开,再传递给execlp函数。

信号:

通知进程已发生某种情况的一种技术,进程如何处理信号有三种选择,1.忽略该信号;2 按系统默认的方式处理 ;3 提供一个函数,信号发生时调用这个函数。

终端键盘上有两种产生信号的方法,分别称为中断键(delete或者crtl+c)和退出健。被用于中断当前的进程,另一种产生信号的方法是调用名为kill的函数。

出错处理:

当unix系统函数出错时,通常返回一个负值,而且整型变量errno通常被设置为具有特定信息的值,在open函数出错时,有大约15种不同的errno值。

头文件errno.h定义了errno以及可以赋予它的各种常量,这些常量都是以字符E开头。

时间值:

当度量一个进程的执行时间时,unix系统使用三个进程时间值:

时钟时间(墙上时间):也就是进程从开始到结束所用的实际时间

用户cpu时间:执行用户指令所用的时间

系统cpu时间:该进程执行内核程序所用时间

后两者时间和常称为cpu时间,执行time()指令,可以得到这三个值。

那么如果多核cpu并行处理指令,会导致时钟时间(wall time)会小于后俩者之和。

系统调用和库函数:

从实现者角度系统调用和库函数之间有重大区别,但是对于用户,区别并不重要。但是应该知道的是,必要时我们可以替代库函数,却无法替代系统调用

以存储器分配函数malloc,它实际上是调用了系统调用函数sbrk。也就是说,很多库函数是调用系统调用,而应用程序既可以调用库函数,也可以调用系统调用。

系统调用和库函数另一个差别是:系统调用通常提供一种最小接口,而库函数通常提供比较复杂的功能。

 

转载于:https://www.cnblogs.com/sichenzhao/p/9320373.html

你可能感兴趣的文章
雅虎开源了TensorFlowOnSpark
查看>>
ERP实施应立足于两点
查看>>
网络安全保险在欧洲更受欢迎
查看>>
三星未及时提供系统更新 荷兰消协把它告上法庭
查看>>
如何处理IT事件管理以避免混乱
查看>>
投资半导体产业不能只想赚快钱
查看>>
物联网确保消费者隐私安全 才能起飞
查看>>
iPhone升級iOS 10变砖 可用iTunes恢复
查看>>
揭秘使用免费WiFi的真实代价
查看>>
思科:网络可见化仍然是安全的数字化转型改造的关键
查看>>
CloudCC CRM梳理CRM软件已经实现的发展
查看>>
《交互式程序设计 第2版》一2.3.2 数组
查看>>
移动互联网金融app 存在信息安全问题
查看>>
Android 开发中使用 SQLite 数据库
查看>>
Android后门GhostCtrl,完美控制设备任意权限并窃取用户数据
查看>>
IBM郭继军:机器学习配合行业经验将帮助企业成就未来
查看>>
Rambus9000万美元收购Inphi存储器互联业务
查看>>
3GPP一反常态提前制定NB-IoT标准有何深意?
查看>>
泉州电信推进渠道互联网化转型
查看>>
影响云计算核心问题的七个要素
查看>>