APUE第一章 UNIX基础知识

前语:本人是半路出家做程序员,实际上应付平时工作中的业务还可以,但是基础知识实在薄弱,当然也跟中国计算机教育有关系,平时跟同事聊天,实际上就算是科班出身,对于计算机本身的了解也知之甚少,因此在毕业两周年到来的时候,给自己确定了以后的技术学习方向,同时也决定了将基础部分补充起来,特来CSDN开这个专题,去学习程序员圣经般著作—《UNIX高级环境编程》,这本书也是被某个同事经常提起,书本比较厚,但是不能操之过急,但是也不要指望一次性就能学完学透,没事回来看看,总有收获,自勉之。

一、UNIX体系结构

操作系统是为了在它们之上运行的程序提供服务的,从严格意思上来说,可以将操作系统看成是个软件,它负责来控制计算机的硬件资源,提供程序运行环境,从这个角度来说,其实还是比较容易理解操作系统的概念,比如说你要读取一个文件,必然是需要通过读取磁盘这种硬件资源才能完成,虽然我们平时写代码可能只需要执行下open或者read等函数就可以完成文件读取,但是真实情况不会那么简单,简单理解可以认为当我们执行了前述函数,实际上是向操作系统发起了一个任务,当任务完成后任务返回结果了,这个说法可能不够严谨,但是比较容易理解。这时候内核这个概念就出来了,而内核与外界程序的中介就是系统调用,在我们学着写C语言代码的时候,会有许多封装好的库函数,这些公用函数库主要就是构建在系统调用至上的,应用程序则既可以调用公用函数库也可以直接调用系统调用,在unix系统中,有一个特殊的应用程序叫着shell程序,这个程序是用户与系统的接口,通过shell我们可以执行其他的应用程序,这几个部分组成的体系结构图如下:

二、文件

这章节之前书中还提到了登录与shell,这两部分我在这里就不讲了,主要原因是用户这块影响最大的实际上是权限问题,后面书中其他章节会涉及到这块,讲的也比这里深入,所以暂且跳过。文件这部分对UNIX及其重要,或许许多人知道,unix的信条之一就是一切皆文件,也就是说无论是设备交互,文件读取,网络连接都可以看成或者抽象成一个文件对待,这块在以后的学习中通过了解API可以知道,太多的unix的东西接口都是很类似和相像的,原因也在这里。

这部分书中讲了几个概念,也就是概念,先了解了解就可以了,第一章的大部分后面会有专门的一个章节来专门讲解。UNIX的文件系统是一种层级结构,起点就是"/"这个根目录。在这里可能有个概念不是好理解,那就是UNIX文件系统是包含目录和文件的,但是在UNIX里面,目录实际上是一个包含目录项的文件,对应了上面一切皆文件的话了。逻辑上说,每个目录项都是一个结构体,里面包含了一个文件名,同时还包含了说明文件属性的信息。文件属性记载着这个文件各种属性的集合,这里面有一项是来指明文件类型的,说明这个文件是目录还是普通文件。

目录中的各个名字成为文件名,只有斜线和空字符不能出现在文件名中,这是因为斜线是用来分隔路径的,空字符用来终止一个路径名的,当创建一个新的目录时,会在该目录下创建两个文件名,分别是"."和"..",分别用来表示指向当前目录和父目录,当然在最高层次的根目录中,他们两都指向当前目录。而由斜线分隔的一个或者多个文件名构成的是路径名,以"/"开始的叫做绝对路径名,否则是相对路径名。比如说"/usr/local/bin",这里面usr,local,bin实际上都是文件名,虽然他们在实际系统里面都是文件夹(目录),但是在这个体系里面,就是文件名。而"/usr/local"连起来的就是路径名,而且是绝对路径,至于"local/bin"则是相对于/usr/的相对路径名。书中提供了一个ls命令简单版本的代码,用来去了解目录层级,大家可以看输出结果,我把书中原来的头文件给去掉了,这样不管谁想只是看看这段代码效果,不需要去把该书配的源码下载下来看,代码如下:

#include <stdlib.h>
#include <stdio.h>
#include <dirent.h>

int main(int argc, char* argv[])
{
    DIR     *dp;
    struct dirent *dirp;

    if (argc != 2) {
        printf("usage: ls directory_name");
        return 0;
    }

    if ((dp = opendir(argv[1])) == NULL) {
        printf("can't open %s", argv[1]);
        return 0;
    }
    while ((dirp = readdir(dp)) != NULL) {
        printf("%s\n", dirp->d_name);
    }
    closedir(dp);
    exit(0);
}

当我们登录系统的时候,实际上都会进入到自己登录用户的一个默认目录,这个叫起始目录,这部分在口令文件中可以看到,还有当我们运行程序的时候都会有一个工作目录,这也是为啥当我们把一个文件放到执行文件的路径下就可以读取的原因,当然我们也可以在程序中修改自己的工作目录,这个部分在后面介绍进程的时候会突出讲到。

三、输入输出

输入输出对计算机系统而言太重要了,也算是最直接最基础的功能,用途广泛,在UNIX系统尤其如此,无论是管道、终端,还是文件、socket,都离不开输入输出这个范畴。这部分也有几个比较重要的概念需要了解,这对于以后进一步深入学习非常重要,首先是文件描述符,这是内核用来标识一个特定进程正在访问的文件,注意,这里说的很清楚,就是文件描述符是跟进程相关的,不同进程操作同一个文件,文件描述符不一定一样,当内核打开一个已有或者创建新文件的时候,就会返回一个文件描述符,而后其他所有的操作,都是针对这个文件描述符来进行。

但是也有例外,对于所有程序而言,当运行该程序的时候,shell都会为这个程序打开3个文件描述符(0,1,2),分别是标准输入,标准输出以及标准错误,如果不做处理,这三个描述符都是链接到终端的,当然如果你愿意,完全可以通过"<"或者">"将这个三个重定向到某个文件,比如ls > 1.txt就会把ls的结果输出到1.txt文件中去。

讲完文件,再讲就是对文件的操作,实际上基本上都是读写操作,I/O操作分为不带缓冲的IO和带缓冲的IO,这两部分都会有专门的章节后面详细讲述,下面的代码只是让你大概了解下IO操作的过程:

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>

#define BUFFSIZE 4096

int main(void)
{
    int     n;
    char    buf[BUFFSIZE];

    while ((n = read(STDIN_FILENO, buf, BUFFSIZE)) > 0) {
        if (write(STDOUT_FILENO, buf, n) != n) {
            printf("write error !\n");
        }
    }

    if (n < 0) {
        printf("read error !\n");
    }

    exit(0);
}

四、程序与进程

这可能是我们最熟悉的部分了,也是我们最经常干的事情,写段代码,跑一下。写完的代码的就是程序,程序实际上就是一个可执行文件,存放在磁盘里面的某个地方,当我们想跑一下的时候,通过内核将该文件读取到内存,然后按照该文件中指令执行,执行的一个实例叫做进程,也就是说如果同时执行两个同样的程序,这时候是有两个进程的,每个进程都会有一个唯一的编码,叫进程ID,程序可以通过getpid函数获取自己当前的进程ID。刚才提到,内核是会把程序文件读入到内存,然后再执行,实际上这个过程就是exec函数的执行过程,exec是进程控制函数的一个,进程控制函数不多,主要就3个,分别是用来执行程序的exec函数,创建进程的fork函数以及waitpid函数,这部分后面也有几个章节来重点介绍。

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>

int main(void)
{
    printf("hello world from process ID %ld\n", (long) getpid());
    exit(0);
}

接下来要说下线程的事情,通常,一个进程只有一个控制线程,但是如果有时候能有多个控制线程分别干其他的事情,那么解决问题的能力就好多了,实际上,线程的概念并不是一开始就有的,所以线程模型的实现与进程模型在很多时候是非常相像的,这个后面章节介绍线程的时候也会提到,连控制线程的函数都与控制进程的函数相类似。一个进程内的所有线程共享同一个地址空间、文件描述符、栈以及进程相关的属性,这个就为了多个任务处理同一个事件提供了可能,同时也带来了一些实现上的困难,那就是多个线程在访问共享数据的同时如何保证数据的一致性,这也是令广大程序员头疼的锁的根源。

五、出错处理

调用过linux库函数的时候都比较熟悉,尤其是read等函数,如果出错的时候都会返回一个负值用来告知用户出错,同时整型变量errno会被设置为具有特定消息的值,通过该值不仅可以知道当前错误类型,还能获取到当前错误的描述,这块只需要注意一点,那就是多线程程序中errno的实现,这部分大家可以搜索相关技术帖了解下,即系统是如何保证同一个进程中当两个线程同时发生错误时保证都能输出对应的错误。

#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>

int main(int argc, char *argv[])
{
    fprintf(stderr, "EACCES: %s\n", strerror(EACCES));
    errno = ENOENT;
    perror(argv[0]);
    exit(0);
}

六、信号

信号是用于通知进程发生了某种情况。这部分请记住一点,信号实际上是系统唯一与进程发生联系的方法方式。这一条很重要,实际上在许多开源的软件上都应用到了这个技术,比如说如果一个服务程序的配置项修改了,如果非常优雅的更新呢,重启肯定不适合,定时获取,这时候就涉及间隔问题,或者如何快速生效,这时候信号就可以做到悄无声息了,所以但凡与进程交互的,都可以往信号上想想。

进程有三种信号处理方式:

1)忽略信号。

2)默认处理,比如说kill程序。

3)自定义信号捕捉函数,这也是前面提到与进程交互的方法的实现方式。这部分也会有一个章节来专门介绍。

整个文章实际上只是简单介绍了UNIX系统的一些基本概念,这些概念其实构成了系统对外的功能框架,后续可能还有网络通信等内容进一步展示,由于本人也是刚刚开始学习,许多知识理解还比较浅,所以介绍的不够明白和严谨,希望大家多多批评,共同进步!

时间: 2024-10-21 02:36:16

APUE第一章 UNIX基础知识的相关文章

UNIX环境高级编程学习笔记(第一章UNIX基础知识)

总所周知,UNIX环境高级编程是一本很经典的书,之前我粗略的看了一遍,感觉理解得不够深入. 听说写博客可以提高自己的水平,因此趁着这个机会我想把它重新看一遍,并把每一章的笔记写在博客里面. 我学习的时候使用的平台是Windows+VMware+debian,使用secureCRT来连接(可以实现多个终端连接). 因为第一章是本书大概的描述,所以第一章的我打算写得详细一点,而且书本的原话占的比例会比较多,重点的东西会用粗体显示出来. 1.1  引言 所有操作系统都为他们所运行的程序提供服务.典型的

第一章 UNIX 基础知识

1.1 Unix体系结构 OS定义为一种软件,它控制计算机硬件资源,提供程序运行环境,一般称其为内核(kernel),它体积小,位于环境中心. 内核的接口为系统调用(system call),共用函数库构建在系统调用上,应用软件既可以使用公用函数库,也可以使用系统调用.shell是一种特殊的应用程序,它为运行其他应用程序提供一个接口. 下图为 UNIX 体系结构: 广义上,OS包括内核和一些软件,例如 Linux 是 GNU 操作系统使用的内核,可以称这种操作系统为 GNU/Linux,但是通常

自学:Unix环境高级编程 第一章 Unix基础知识

1.2 Unix体系结构 内核(kernel):控制计算机硬件资源,提供程序运行环境. 系统调用(system call):内核的接口. 公用函数库构建在系统调用接口之上. 应用程序既可使用公用函数库,也可使用系统调用 shell是一个特殊的应用程序,为运行其他应用程序提供了一个接口. 1.3 登录    1.登录名 系统在其口令文件(通常是/etc/passwd文件)中查看登录名. 例如:sar:x:205:105:Stephen Rago:/home/sar:/bin/ksh 口令文件中的登

第一章 Unix基础知识

unix环境高级编程,尤晋元,2000年 只是把书里的代码敲一遍跑一下,熟悉一下书里的东西,没什么特别的: #include <stdio.h> #include <stdlib.h> #include <unistd.h> // list directory content int ls(int, char**); // copy input to output int IO_Nobuffer(); int standardio(); int shell(int, c

APUE学习笔记:第一章 UNUX基础知识

1.2 UNIX体系结构 从严格意义上,可将操作系统定义为一种软件(内核),它控制计算机硬件资源,提供程序运行环境.内核的接口被称为系统调用.公用函数库构建在系统调用接口之上,应用软件即可使用公用函数库,也可使用系统调用.shell是一种特殊的应用程序,它为运行其他应用程序提供了一个接口 从广义上,操作系统包括了内核和一些其他软件,这些软件使得计算机能够发挥作用,并给予计算机以独有的特性(软件包括系统实用程序,应用软件,shell以及公用函数库等) 1.3  shell shell是一个命令行解

第一章 计算机基础知识

第一章 计算机基础知识 第一部分 概述 1.1946年2月15日,第一台计算机 ENIAC 2.物理原件(电子原件) 第一代:电子管.第二代:晶体管.第三代:中小规模集成电路.第四代:超大规模集成电路.第五代:超导材料.第六代:人工智能.#考试考到第四代. 3.计算机的分类 巨型机,大型机,中型机,小型机,微型机 现在的巨型机也是存在的 4.微处理器(CPU.中央处理器)由控制器.寄存器.运算器组成 第二部分 微机系统的组成 CPU>内存>外存 #速度 CPU和内存之间有一个CACHE,叫做高

高项3.7日第一次课,第一章信息化基础知识与第二章信息系统服务管理梳理

第一章 信息化的基础知识 1.国家信息化体系要素: 主要包括6要素,信息技术应用(龙头).信息资源(关键).信息网络(必要手段).信息技术产业(基础).信息化人才(成功之本).信息化法规政策和规范(保障). 2.电子政务: 电子政务建设的指导原则: (1)统一规划,加强领导. (2)需求主导,突出重点. (3)统一规划,拉动产业. (4)统一标准,保障安全. 主要任务: (1)电子政务网络由政务内网和政务外网构成,两网之间物理隔离,政务外网与互联网之间逻辑隔离.政务内网主要是副省级以上政务部门的

第一章 Shell基础知识

1.1 简介 Shell是一个C语言编写的脚本语言,它是用户与Linux的桥梁,用户输入命令交给Shell处理,Shell将相应的操作传递给内核(Kernel),内核把处理的结果输出给用户. 下面是处理流程示意图: Shell既然是工作在Linux内核之上,那我们也有必要知道下Linux相关知识. Linux是一套免费试用和自由传播的类Unix操作系统,是一个基于POSIX和UNIX的多用户.多任务.支持多线程和多CPU的操作系统. 1983年9月27日,Richard Stallman(理查德

第一章 Python基础知识

1.1 介绍  1.1.1 特点 Python是一种面向对象.解释型计算机程序设计语言.语法简洁清晰,强制用空白符作为语句缩进. Python具有丰富和强大的库,又被称为胶水语言.能把其他语言(主要C/C++)写的模块很轻松的结合在一起. 1.1.2 应用领域 Web网站:有很多优秀的开源Web框架,比如Django(最流行).Tornado(轻量级.异步).Flask(微型).Web.py(简单)等. 数据采集:有好用的http库,比如urllib2.requests等.还有高级的屏幕爬取及网