总所周知,UNIX环境高级编程是一本很经典的书,之前我粗略的看了一遍,感觉理解得不够深入。

听说写博客可以提高自己的水平,因此趁着这个机会我想把它重新看一遍,并把每一章的笔记写在博客里面。

我学习的时候使用的平台是Windows+VMware+debian,使用secureCRT来连接(可以实现多个终端连接)。

因为第一章是本书大概的描述,所以第一章的我打算写得详细一点,而且书本的原话占的比例会比较多,重点的东西会用粗体显示出来。

1.1  引言

所有操作系统都为他们所运行的程序提供服务。典型的服务包括:执行新程序、打开文件、读文件、分配存储区以及获取当前时间等,

本书集中阐述不同版本的UNIX操作系统所提供的服务。

本章会简要的介绍UNIX提供的各种服务,在以后的各章中将对这些概念做更详细的说明。

1.2  UNIX体系结构

从严格意义上说,可将操作系统定义为一种软件,它控制计算机硬件资源,提供程序运行环境。我们通常将这种软件称为内核

下图显示了UNIX系统的体系结构,其它部分下面会逐个讲到。

1.3  登录

1 登录名

用户在登录UNIX系统时,先键入登录名,然后键入口令。系统在其口令文件(通常是/etc/passwd文件)中查看用户名。

2 shell

用户登录后,系统通常先显示一些系统信息,然后用户就可以向shell程序键入命令。

shell是一个命令行解释器,它读取用户输入,然后执行命令。

1.4  文件和目录

1 文件系统

UNIX文件系统是目录和文件的一种层次结构,所有东西的起点都是根的目录,这个目录名称是一个字符“/”

目录是一个包含目录项的文件,可以认为每个目录项都包含一个文件名,同时还包含该文件属性的信息(ls -l可以查看)。第四章会详细说明文件的各种属性。

2 文件名

目录中的各个名字成为文件名,创建目录时会自动创建两个文件名:.(当前目录)和..(父目录)   (可见为什么 cd .. 会回到父目录)

3 路径名

已斜线开头的路径名称成为绝对路径名(可以理解为以根目录开头的相对路径名),否则为相对路径名。

不难列出一个目录中所有文件的名字,下面是ls(1)命令的简要实现

其中apue.h可以通过网上下载,http://blog.csdn.net/istruth/article/details/44201827有下载地址和使用的方法,后面章节会详细的给出下列函数的用法。

  1. #include "apue.h"
  2. #include <dirent.h>
  3.  
  4. int main(int argc,char *argv[])
  5. {
  6. DIR *dp;
  7. struct dirent *dirp;
  8. if(argc!=)
  9. err_quit("usage:ls directory_name");
  10. if((dp=opendir(argv[]))==NULL)
  11. err_sys("can't open %s",argv[]);
  12. while((dirp=readdir(dp))!=NULL)
  13. printf("%s\n",dirp->d_name);
  14. closedir(dp);
  15. exit();
  16. }

可以使用gcc编译该文件  执行命令cc myls.c进行编译   会生成a.out文件  执行./a.out命令来运行  (./代表当前目录,如果不指定,系统会在环境变量中设置的路径中找可执行文件)

4  工作目录

每个进程都有一个工作目录,有时称其为当前工作目录,进程可以用chdir函数更改其工作目录

5 起始目录

登录时,工作目录设置为起始目录,该起始目录从口令文件中相应用户的登录项中取得。

1.5  输入与输出

1 文件描述符

文件描述符通常是一个小的非负整数,用来标识一个特定进程正在访问的文件。当内核打开一个现有文件或创建一个新文件时,

它都返回一个文件描述符,可以通过这个文件描述符进行读写文件

2  标准输入、标准输出和标准错误

每当运行一个新程序时,所有的shell都为其打开3个文件描述符,即标准输入(0)、标准输出(1)和标准错误(2),如果不做特殊处理,

则这3个描述符都链接到终端。

3  不带缓冲的I/O

函数open、read、write、lseek以及close提供了不带缓冲的I/O。这些函数都使用文件描述符

下面程序展示了如何复制UNIX下的普通文件

  1. #include "apue.h"
  2.  
  3. #define BUFFSIZE 4096
  4.  
  5. int main(void)
  6. {
  7. int n;
  8. char buf[BUFFSIZE];
  9. while((n=read(STDIN_FILENO,buf,BUFFSIZE))>)
  10. if(write(STDOUT_FILENO,buf,n)!=n)
  11. err_sys("write error");
  12. if(n<)
  13. err_sys("read error");
  14. exit();
  15. }

大多数shell都提供一种方法,使其中任何一个或所有这3个描述符都能重定向到某个文件。例如ls > file.list 可以将ls的输出(标准输出 文件描述符为1)重定向到名为file.list的文件。

如下执行上面的程序: ./a.out > data 可以把程序的标准输出重定向到文件data   ./a.out < infile > outfile 把程序的标准输入重定向到infile  把标准输出重定向到outfile,实现了文件的复制。

4  标准I/O

标准I/O 为那些不带缓冲的I/O函数提供了一个带缓冲的接口,下面演示使用标准I/O复制UNIX文件

  1. #include "apue.h"
  2.  
  3. int main(void)
  4. {
  5. int c;
  6. while((c=getc(stdin))!=EOF)
  7. if(putc(c,stdout)==EOF)
  8. err_sys("output error");
  9. if(ferror(stdin))
  10. err_sys("input error");
  11. exit();
  12. }

1.6 程序与进程

1 程序

程序是一个存储在磁盘上某个目录中的可执行文件

2 进程和进程ID

程序的执行实例被称为进程,UNIX系统确保每个进程都有一个唯一的数字标识符,称为进程ID。进程ID总是一个非负整数

下面程序用于打印进程ID

  1. #include "apue.h"
  2.  
  3. int main(void)
  4. {
  5. printf("hello world from process ID %ld\n",(long)getpid());
  6. exit();
  7. }

3 进程控制

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

UNIX系统的进程控制功能可以用一个简单得程序说明,下面程序从标准输入读取命令,然后执行命令,类似于shell程序的基本实施部分。

  1. #include "apue.h"
  2. #include <sys/wait.h>
  3.  
  4. int main(void)
  5. {
  6. char buf[MAXLINE];
  7. pid_t pid;
  8. int status;
  9. printf("%% ");
  10. while(fgets(buf,MAXLINE,stdin)!=NULL)
  11. {
  12. if(buf[strlen(buf)-]=='\n')
  13. buf[strlen(buf)-]=;
  14. if((pid=fork())<)
  15. err_sys("fork error");
  16. else if(pid==)
  17. {
  18. execlp(buf,buf,(char *));
  19. err_ret("couldn't execute:%s",buf);
  20. exit();
  21. }
  22. if((pid=waitpid(pid,&status,))<)
  23. err_sys("waitpid error");
  24. printf("%% ");
  25. }
  26. exit();
  27. }

4  线程和线程ID

与进程相同,线程也用ID标识。但是,线程ID只在它所属的进程内起作用。

1.7  出错处理

当UNIX系统函数出错时,通常会返回一个负值,而且整形变量errno通常被设置为具有特定信息的值。

文件<error.h>中定义了error以及可以赋予它的各种常量。

C标准定义了两个函数,用于打印出错信息

  1. #include <string.h>
  2. char *strerror(int errnum);

strerror函数将errnm(通常就是error值)映射为一个出错消息字符串,并且返回此字符串的指针。

  1. #include <stdio.h>
  2. void perror(const char *msg);

perror函数基于errno的当前值,在标准错误上产生一条出错信息,然后返回。

下面程序显示这两个出错函数的使用方法

  1. #include "apue.h"
  2. #include <errno.h>
  3.  
  4. int main(int argc,char *argv[])
  5. {
  6. fprintf(stderr,"EACCES:%s\n",strerror(EACCES));
  7. errno=ENOENT;
  8. perror(argv[]);
  9. exit();
  10. }

1.8  用户标识

1 用户ID

用户ID是一个数值,用来确定一个用户。用户ID为0为根用户或超级用户,超级用户对系统有自由的支配权。

2 组ID

组ID是由系统管理员在指定用户登录名时分配的,可以把多个用户分成一组。

下面程序用于打印用户ID和组ID

  1. #include "apue.h"
  2.  
  3. int main(void)
  4. {
  5. printf("uid=%d,gid=%d\n",getuid(),getgid());
  6. exit();
  7. }

3 附属组ID

除了在口令文件中对一个登录名指定一个组ID之外,大多数UNIX系统版本还允许一个用户属于另外一些组。

1.9 信号

信号用于通知进程发生了某种情况。例如,若某一进程执行除法操作,其除数为0,则将名为SIGFPE(浮点异常)的信号发送给进程。

进程有以下3种处理信号的方式:

1 忽略信号

2 按系统默认方式处理

3 提供一个函数,信号发生时调用该函数,这被称为捕捉该信号。

终端键盘上有两种产生信号的方法,分别称为中断键(通常是Delete或Ctrl+C)和退出键(通常是Ctrl+\)

修改之前的shell实例,使程序可以捕获SIGINT信号,我们会在第10章详细的介绍信号。

  1. #include "apue.h"
  2. #include <sys/wait.h>
  3.  
  4. static void sig_int(int);
  5.  
  6. int main(void)
  7. {
  8. char buf[MAXLINE];
  9. pid_t pid;
  10. int status;
  11. if(signal(SIGINT,sig_int)==SIG_ERR);
  12. err_sys("signal error");
  13. printf("%% ");
  14. while(fgets(buf,MAXLINE,stdin)!=NULL)
  15. {
  16. if(buf[strlen(buf)-]=='\n')
  17. buf[strlen(buf)-]=;
  18. if((pid=fork())<)
  19. err_sys("fork error");
  20. else if(pid==)
  21. {
  22. execlp(buf,buf,(char *));
  23. err_ret("couldn't execute:%s",buf);
  24. exit();
  25. }
  26. if((pid=waitpid(pid,&status,))<)
  27. err_sys("waitpid error");
  28. printf("%% ");
  29. }
  30. exit();
  31. }
  32. void sig_int(int signo)
  33. {
  34. printf("interrupt\n%%");
  35. }

1.10  时间值

历史上,UNIX系统使用过两种不同的时间值

1 日历时间。该值是从1970年1月1日00:00:00这个特定时间以来所经过的秒数的累计值。

2 进程时间。也被称为CPU时间

当度量一个进程的执行时间时,UNIX系统为一个进程维护了3个进程时间值

时钟时间  即进程运行的时间总量,其值与系统中同时运行的进程数有关

用户CPU时间  执行用户指令所用的时间量

 系统CPU时间  执行系统调用的时间

1.11 系统调用和库函数

系统调用提供的函数如open, close, read, write, ioctl等,系统调用发生在内核空间

标准C库函数提供的文件操作函数如fopen, fread, fwrite, fclose, fflush, fseek等属于库函数,底层也是通过系统调用来实现的

apue学习笔记(第一章UNIX基础知识)的更多相关文章

  1. 《UNIX环境高级编程》(APUE) 笔记第一章 - UNIX基础知识

    1 - UNIX基础知识 Github 地址 1. 操作系统 可将操作系统定义为一种软件,它控制计算机硬件资源,提供程序运行环境.通常将这种软件称为 内核 (kernel) .( Linux 是 GN ...

  2. UNIX环境高级编程--第一章 UNIX基础知识

    第一章 UNIX基础知识 1.2 UNIX体系结构   从严格意义上说,可将操作系统定义为一种软件,它控制计算机硬件资源,提供程序运行环境.我们将这种软件称为内核(kernel),因为 它相对较小,且 ...

  3. 第一章 UNIX 基础知识

    1.1 Unix体系结构 OS定义为一种软件,它控制计算机硬件资源,提供程序运行环境,一般称其为内核(kernel),它体积小,位于环境中心. 内核的接口为系统调用(system call),共用函数 ...

  4. Python 学习系列----第一章:基础知识

    1.1 常量-----不能改变它的值 1.2 数 在Python 中数可以分为整数.浮点数和复数. PS:在Python中不用区分'long int'类型.默认的整数类型可以任意长.(译者注:长度应该 ...

  5. Web程序设计笔记-第一章:基础知识

    1,Web服务器 (1)Web服务器操作 Web浏览器通过向服务器发送URL来与Web服务器进行通信.URL可以指定两种不同资源中的一种:某个文件或者某个程序. Web客户机和Web服务器之间所有的通 ...

  6. [Python笔记][第一章Python基础]

    2016/1/27学习内容 第一章 Python基础 Python内置函数 见Python内置函数.md del命令 显式删除操作,列表中也可以使用. 基本输入输出 input() 读入进来永远是字符 ...

  7. UNIX环境高级编程 第1章 UNIX基础知识

    所有操作系统都为运行在它之上的程序提供各种服务,典型的服务包括:执行新程序.打开文件.读写文件.分配存储空间.提供时间等. UNIX体系结构 严格来说,操作系统是一种软件,它控制计算机硬件资源,提供程 ...

  8. C语言学习笔记第一章——开篇

    本文章B站有对应视频 (本文图片.部分文字引用c primer plus) 什么是C语言 顾名思义,c语言是一门语言,但是和我们所讲的话不同,它是一门编程语言,是为了让机器可以听懂人的意思所以编写的一 ...

  9. 《跟我学Shiro》学习笔记 第一章:Shiro简介

    前言 现在在学习Shiro,参照着张开涛老师的博客进行学习,然后自己写博客记录一下学习中的知识点,一来可以加深理解,二来以后遗忘了可以查阅.没有学习过Shiro的小伙伴,也可以和我一起学习,大家共同进 ...

随机推荐

  1. 为什么js引入页面后不起作用?

    为什么js引入页面后不起作用? 例如常见的报错:Uncaught ReferenceError: $ is not defined. 可能出现这种情况的原因如下: 原因一: 引入js的位置不对,应在使 ...

  2. 关于java1.7集合源码阅读

    工作中每天都会和java集合打交道,虽然以前也看过jdk源码的实现,但有些东西时间长了还是会遗忘,或者有些实现在新版本中有了新的变化,俗话说"温故而知新",所以打算再阅读一下相关源 ...

  3. Java反射常用API汇总

    “JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意方法和属性” 一.类对象的获取 1.通过对象获取 Object obj = ne ...

  4. 经常用的Jquery图片轮转

    1.HTML结构 <div class="main_view">                 <div class="window"> ...

  5. 大牛教你如何循序渐进,有效的学习JavaScript?

    首先要说明的是,咱现在不是高手,最多还是一个半桶水,算是入了JS的门.谈不上经验,都是一些教训. 这个时候有人要说,“靠,你丫半桶水,凭啥教我们”.您先别急着骂,先听我说! 你叫一个大学生去教小学数学 ...

  6. Netty源码学习(六)ChannelPipeline

    0. ChannelPipeline简介 ChannelPipeline = Channel + Pipeline,也就是说首先它与Channel绑定,然后它是起到类似于管道的作用:字节流在Chann ...

  7. 陕西师范大学第七届程序设计竞赛网络同步赛 J 黑猫的小老弟【数论/法拉数列/欧拉函数】

    链接:https://www.nowcoder.com/acm/contest/121/J来源:牛客网 题目描述 大家知道,黑猫有很多的迷弟迷妹,当然也有相亲相爱的基友,这其中就有一些二五仔是黑猫的小 ...

  8. poj2763(树链剖分 - 边权)

    poj2763 题意 给定一个树形图,某人原来在 s 点,每条边(路)有通过的时间花费,有两种操作:1. 查询某人到 u 点花费的时间 2. 更新某条路的时间花费. 分析 权值在边上,可以把它们 &q ...

  9. 八. 输入输出(IO)操作4.面向字节的输入输出流

    字节流以字节为传输单位,用来读写8位的数据,除了能够处理纯文本文件之外,还能用来处理二进制文件的数据.InputStream类和OutputStream类是所有字节流的父类. InputStream类 ...

  10. Codeforces Round #228 (Div. 1) 388B Fox and Minimal path

    链接:http://codeforces.com/problemset/problem/388/B [题意] 给出一个整数K,构造出刚好含有K条从1到2的最短路的图. [分析] 由于是要自己构造图,当 ...