APUE 读书笔记(一)

应老大要求,从今天开始APUE的读书笔记。其实就是一些比较需要注意的点

第一章. UNIX基础知识

   一、登陆

拿到一台Linux主机,最新开始的是登陆。

Linux 登陆的验证是靠 /etc/passwd 这个文件的。

$ grep kiosk /etc/passwd
kiosk:x:1000:1000:kiosk:/home/kiosk:/bin/bash

这些子段分别是用户名,加密后的密码,用户id,用户组id,描述,家目录,使用的shell。

整个登陆过程如下:

      read /etc/inittab                    get username in tty             get password

init ---------------------> mingetty ---------------------------> login ------------------/etc/pam.d-----------> call PAM modules -------------> act/rej

Linux PAM是一个通用的认证机制,是以库的模式。

二、文件和目录

文件系统:

            目录(directory)是一个包含目录项的文件,在逻辑上,可以认为每个目录项都包含一个文件名,同时还包含说明该文件属性的信息。文件属性是:文件类型,文件长度,文件所有者,文件的许可权(例如,其他用户能否能访问该文件),文件最后的修改时间等,可以使用stat和fstat去查看详细信息。

使用stat命令去查看文件的详细信息。

$ stat google-chrome.desktop 
  File: ‘google-chrome.desktop’
  Size: 8392      	Blocks: 24         IO Block: 4096   regular file
Device: fd02h/64770d	Inode: 134751621   Links: 1
Access: (0755/-rwxr-xr-x)  Uid: (    0/    root)   Gid: (    0/    root)
Context: unconfined_u:object_r:user_home_t:s0
Access: 2018-03-19 15:06:39.280035865 +0800
Modify: 2018-03-08 17:50:18.060889472 +0800
Change: 2018-03-08 17:50:26.282852535 +0800
 Birth: -

解释一下:

- File:显示文件名
- Size:显示文件大小
- Blocks:文件使用的数据块总数
- IO Block:IO块大小
- regular file:文件类型(常规文件)
- Device:设备编号
- Inode:Inode号
- Links:链接数
- Access:文件的权限

- Gid、Uid:文件所有权的Gid和Uid。

三、输入和输出

首先清楚文字描述符的概念。

         文字描述符是一个小的非负整数,内核用以标识一个特定进程正在存访的文件。当内核打开一个现存文件或创建一个新文件时,它就返回一个文件描述符。当读、写文件时,就可使用它。

        按惯例,每当运行一个新程序时,所有的 s h e l l都为其打开三个文件描述符:标准输入、标准输出以及标准出错。如果像简单命令 l s那样没有做什么特殊处理,则这三个描述符都连向终端。

         文件描述符的本质是 数组元素的下标。


            右侧的表称为i节点表,在整个系统中只有1张。该表可以视为结构体数组,该数组的一个元素对应于一个物理文件。

           中间的表称为文件表,在整个系统中只有1张。该表可以视为结构体数组,一个结构体中有很多字段,其中有3个字段比较重要:

           左侧的表称为文件描述符表,每个进程有且仅有1张。该表可以视为指针数组,数组的元素指向文件表的一个元素。最重要的是:数组元素的下标就是大名鼎鼎的文件描述符。

           open系统调用执行的过程:新建一个i节点表元素,打开的物理文件(如果对应于该物理文件的i节点元素已经建立,就不做任何操作);新建一个文件表的元素,根据open的第2个参数设置file status flags字段,将current file offset字段置0,将v-node ptr指向刚建立的i节点表元素;在文件描述符表中,寻找1个尚未使用的元素,在该元素中填入一个指针值,让其指向刚建立的文件表元素。最重要的是:将该元素的下标作为open的返回值返回。

   不带缓存的IO和标准IO

       不带缓存的IO是指 函数open、read、write、lseek以及close提供了不用缓存的 I / O。这些函数都用文件描述符进行工作。   如read和write函数都有一个参数--- ‘buf’。这个参数用来指向读取或者写入的地方。通常我们都是自己新建一个数组,用来读取或者写入,这就是不带缓存的IO,需要自己考虑读取内容的存放位置(或者写入内容的存放位置),同时还得考虑读取或者写入的长度。

     与之相对的就是标准IO。最常见的是printf()。

四、进程控制

     有三个用于进程控制的主要函数: fork、exec和waitpid(exec函数有六种变体,但经常把它们统称为exec函数)。

首先看下面的代码

#include <sys/types.h>
#include <sys/wait.h>
#include "ourhdr.h"
#include "myerror.h"

int main(void){
    char buf[MAXLINE];
    pid_t pid;
    int status;

    printf("%% ");
    while(fgets(buf,MAXLINE,stdin) != NULL) {
        buf[strlen(buf) - 1] = 0;  /*replace newline with null*/
        if ((pid=fork()) < 0)
           err_sys("fork error");

        else if (pid == 0) {       /*child*/
           execlp(buf,buf,(char *) 0);
           err_ret("couldn't execute: %s",buf);
           exit(127);
        }

        if ((pid = waitpid(pid,&status,0)) < 0)  /*parent*/
           err_sys("waitpid error");
        printf("%% ");
    }
    exit(0);
}

          调用fork创建一个新进程。新进程是调用进程的复制品,故称调用进程为父进程,新创建的进程为子进程。 fork对父进程返回新子进程的非负进程ID,对子进程则返回0。因为fork创建一新进程,所以说它被调用一次 (由父进程),但返回两次(在父进程中和在子进程中 )。

         在子进程中,调用 execlp以执行从标准输入读入的命令。这就用新的程序文件替换了子进程。fork和跟随其后的exec的组合是某些操作系统所称的产生一个新进程。

         子进程调用 execlp执行新程序文件,而父进程希望等待子进程终止,这一要求由调用waitpid实现,其参数指定要等待的进程 (在这里, pid参数是子进程 I D )。waitpid函数也返回子进程的终止状态( status变量)。在此简单程序中,没有使用该值。如果需要,可以用此值精确地确定子进程是如何终止的。

$ ./a.out 
% date
2018年 03月 19日 星期一 17:24:24 CST
% pwd
/home/kiosk/C/apue
% 

五、UNIX时间值

UNIX中有三个时间值。

时钟时间,用户cpu时间,系统cpu时间。

时钟时间(墙上时钟时间wall clock time):从进程从开始运行到结束,时钟走过的时间,这其中包含了进程在阻塞和等待状态的时间。

用户CPU时间:就是用户的进程获得了CPU资源以后,在用户态执行的时间。

系统CPU时间:用户进程获得了CPU资源以后,在内核态的执行时间。

进程的三种状态为阻塞、就绪、运行。

   时钟时间 = 阻塞时间 + 就绪时间 +运行时间
   用户CPU时间 = 运行状态下用户空间的时间

   系统CPU时间 =  运行状态下系统空间的时间。

$ time grep "_POSIX_SOURCE" /usr/lib64/*.h &> /dev/null

real	0m0.004s
user	0m0.003s
sys	0m0.001s



发布了146 篇原创文章 · 获赞 94 · 访问量 24万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章