APUE(1)----UNIX基础知识

一、UNIX体系结构

  所有操作系统都为他们所运行的程序提供服务,典型的服务包括:执行新程序、打开文件、读文件、分配存储区等。严格意义上来说,操作系统可以定义为一种软件,它控制计算机硬件资源,提供程序运行环境。我们也将这种软件成为内核,因为它相对较小,并且位于环境的核心。内核的接口被称为系统调用。公共函数库构建在之上,普通的应用程序可以调用系统调用,也可以调用公共函数库。shell是一个特殊的应用程序,位运行其他应用程序提供了一个接口。

二、文件和目录

1.文件系统

  UNXI文件系统是目录和文件的一种层次结构,所有东西的起点称为根(root)的目录,这个目录的名称是一个字符“/”。目录是一个包含目录项的文件,由文件名和文件属性(文件类型、文件大小、文件所有者、文件权限等)组成。这里需要注意的是逻辑视图和实际存放在磁盘上的方式是不同的。UNIX文件系统的大多数实现并不在目录项中存放属性,这是因为当一个文件具有多个硬链接时,很难保持多个属性副本之间的同步。

2.文件名和路径名

  创建新目录时会自动创建两个文件名:“.”指向当前目录,“..”指向父目录,在最高层次,二者指向相同。由斜线分隔的一个或多个文件名组成的序列构成路径名,以斜线开头的路径名称为绝对路径名,否则称为相对路径名。

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

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

        if(2 != argc)
        {
                printf("usage: ls directory_name\n");
                return -1;
        }

        if(NULL == (dp = opendir(argv[1])))
        {
                printf("can‘t open %s\n", argv[1]);
                return -1;
        }

        while(NULL != (dirp = readdir(dp)))
        {
                printf("%s\n", dirp->d_name);
        }

        closedir(dp);
        exit(0);
}

1-1:列出一个目录中的所有文件

3.工作目录和起始目录

  每个进程都有一个工作目录,所有相对路径名都从工作目录开始解释,进程可以用chdir函数更改其工作目录。登陆时,工作目录设置为起始目录,这个目录是从口令文件中相应用户的登录项中获取的。

三、输入和输出

1.文件描述符

  文件描述符通常是一个小的非负整数,内核用以标识一个特定进程正在访问的文件。当内核打开一个先用文件或创建一个新文件时,它都返回一个文件描述符,在读写文件时,可以使用这个文件描述符。按惯例,每当运行一个新程序时,所有的shell都为其打开3个文件描述符,即标准输入、标准输出以及标准错误,如果不做特殊处理,这三个文件描述符都链接向终端。

2.不带缓冲的I/O

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

#include<unistd.h>
#include<stdio.h>
#include<stdlib.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");
                        return -1;
                }
        }

        if(n > 0)
        {
                printf("read error.\n");
                return -1;
        }

        exit(0);
}

1-2:将标准输入复制到标准输出

注释:1.头文件<unistd.h>包含了很多UNIX系统服务的函数原型,STDID_FILENO/STDOUT_FILENO,以及read/write都定义在其中。2.read函数返回其读取到的字节数,当发生错误时,read返回-1;3输入ctrl+D作为文件结束符,终止程序;

3.标准I/O

  标准I/O函数为那些不带缓冲I/O函数提供了一个带缓冲的接口。使用标准I/O函数无需担心如何选取最佳的缓冲区大小,不用像上例那样需要定义BUFFSIZE。并且还简化了对输入行的处理。

#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
int main(void)
{
        int c;
        while((c = getc(stdin)) != EOF)
        {
                if(putc(c, stdout) == EOF)
                {
                        printf("output error.\n");
                        return -1;
                }
        }

        if(ferror(stdin))
        {
                printf("input error.\n");
        }

        exit(0);
}

1-3:用标准I/O将标准输入复制到标准输出

四、程序和进程

1.程序、进程和进程ID

  程序是一个存储在磁盘上某个目录中的可执行文件。内核使用exec函数将程序读入内存,并执行程序。程序的执行实例称为进程,每一个进程都有一个唯一的数字标识符,被称为进程ID(非负整数)。

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

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

1-4:打印进程ID

2.进程控制

  进程控制主要函数:fork、exec和waitpid。

#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include<unistd.h>
#include<sys/wait.h>

#define MAXLINE 1024

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

        printf("%% ");

        while(NULL != (fgets(buff, MAXLINE, stdin)))
        {
                if(‘\n‘ == buff[strlen(buff) - 1])
                {
                        buff[strlen(buff) - 1] = 0;
                }

                if(0 > (pid = fork()))
                {
                        printf("fork error\n");
                        return -1;
                }
                else if(0 == pid)
                {
                        execlp(buff, buff, (char *) 0);
                        printf("couldn‘t execute:%s\n", buff);
                        return -1;
                }

                if(0 > (pid == waitpid(pid, &status, 0)))
                {
                        printf("wait pid error\n");
                }

                printf("%% ");
        }
}

1-5:从标准输入读命令并执行

注释:1.fgets是一个标准I/O函数,一次读取一行。和read的区别在于自己管理缓冲区,不返回读取的长度,在读取的末尾加入"\n"。而execlp要求参数以null结束,所以需要进行替换;2.fork调用一次,返回两次,在子进程中返回0,父进程返回子进程PID;3.execlp以执行从标准输入读取的命令,这就用新的程序文件替换了子进程原先执行的程序文件;4.父进程和子进程同步是通过waipid实现的。

3.线程和线程ID

  一个进程内的所有线程共享同一地址空间、文件描述符、栈以及与进程相关的属性。因为他们能访问同意存储区,所以各线程在访问共享数据时需要采取同步措施以避免不一致性。和进程ID相同, 线程也有ID,但是线程ID只在它所属的进程内其作用。

五、出错处理

  当UNIX系统函数出错时,通常会返回一个负值,而且整形变量errno通常被设置为具有特定信息的值。对于errno应当注意两条规则:1.如果没有出错,其值不会被例程清楚,因此,仅当函数的返回值指明出错时,才检验其值;2.任何函数都不会将errno值设为0.

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

int main(int argc, char * argv[])
{
        fprintf(stderr, "EACCES: %s\n", strerror(EACCES));

        errno = ENOENT;
        perror(argv[0]);
        exit(0);
}

1-6:例示strerror和perror

注释:1.我们将程序名(argv[0])作为参数传递给main,这是一个标准的UNIX惯例。
六、用户标识

  口令文件登录项中的用户ID是一个数值,它向系统标识不同的用户。根用户的ID为0.

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

int main(void)
{
        printf("uid = %d, gid = %d\n", getuid(), getgid());
        exit(0);
}

1-7:打印用户ID和组ID

七、信号

  信号(signal)用于通知进程发生了某种情况。进程有以下三种处理方式:1.忽略信号;2.按系统默认方式处理;3.提供一个函数。该信号发生时调用该函数。当向一个进程发送信号时,我们必须是那个进程的所有者或者是超级用户。

#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include<unistd.h>
#include<sys/wait.h>

#define MAXLINE 1024

static void sig_int(int);

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

    if(signal(SIGINT, sig_int) == SIG_ERR)
    {
        printf("signal error\n");
        return -1;
    }

    printf("%% ");

    while(NULL != (fgets(buff, MAXLINE, stdin)))
    {
        if(‘\n‘ == buff[strlen(buff) - 1])
        {
            buff[strlen(buff) - 1] = 0;
        }

        if(0 > (pid = fork()))
        {
            printf("fork error\n");
            return -1;
        }
        else if(0 == pid)
        {
            execlp(buff, buff, (char *) 0);
            printf("couldn‘t execute:%s\n", buff);
            return -1;
        }

        if(0 > (pid == waitpid(pid, &status, 0)))
        {
            printf("wait pid error\n");
        }

        printf("%% ");
    }

}

void sig_int(int signo)
{
    printf("interrupt \n%% ");
}

1-8:从标准输入读命令并执行

八、时间值

  UNIX系统为一个进程维护了3个进程时间值:1.时钟时间:进程运行的时间总量,其值与系统中同时运行的进程数有关;2.用户CPU时间:执行用户指令所用的时间量;3.系统CPU时间:为该进程执行内核程序所经历的时间。2和3之和又称为CPU时间。

九、系统调用和库函数

  从实现者的角度来看,系统调用和库函数之间有根本的区别,但从用户的角度来看,其区别不重要。用户可以替换库函数,但是不能替换系统调用。并且系统调用通常提供一种最小接口,而库函数通常提供比较复杂的功能。

时间: 2024-10-28 15:23:17

APUE(1)----UNIX基础知识的相关文章

APUE 学习笔记(一) Unix基础知识

1. Unix 体系结构 内核的接口被称为系统调用 公用函数库构建在系统调用接口之上 应用软件既可以调用公用函数库,也可以直接进行系统调用 2. 文件和目录 目录操作函数:opendir---> readdir---> closedir struct dirent 结构体 stat 系统调用 3.程序.进程.线程 程序:存放在磁盘上.并处于某个目录中的一个可执行文件.使用exec系列函数将程序从磁盘读入存储器,并使其执行 进程:程序的执行实体.进程控制的3个函数:fork.exec.waitp

APUE第一章 UNIX基础知识

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

UNIX 基础知识

登陆  1.登录名 系统在其 口令文件(通常是/etc/passwd文件) 中查看用户名,口令文件中包含了有关用户的信息. 2.shell shell是一个命令解析器,读取用户输入的内容,然后执行命令.   文件和目录 1.文件系统 UNIX文件系统是 目录 和 文件 的一种层次结构. 所有 的起点成为根(root)目录, 根目录的名称是一个” / ”           目录 是一个包含目录项的文件. 可以认为每个目录项都包含一个文件名,同时还包含文件属性的信息(stat和fstat函数返回包

UNIX,基础知识,文件IO,文件和目录

2015.1.27星期二,早晨阴天,中午下雪了今天上午老师不上课,程序语句,记一下:main(void){ int c; while((c = getc(stdin)) != EOF) if(putc(c,stdout) == EOF) 将字符写到标准输出 err_sys("output error"); if(ferror(stdin)) err_sys("input error"); exit(0);} 从标准输入读命令并执行:int main(){ char

apue- chapter 1 UNIX基础知识

1.C++实现ls命令 #include<dirent.h> #include<stdlib.h> #include<iostream> #include "apue.h" using namespace std; int main(int argc,char * argv[]){ DIR *d struct dirent *dirp; if(argc!=2){ cout<<"usage: ls directory_name&q

UNIX基础知识

一.UNIX 系统 UNIX内核的接口称之为系统调用.公用函数库构建在系统调用接口之上.应用程序既可以使用公用函数库,也可以使用系统调用. UNIX shell 是一个特殊的应用程序,它为其他应用程序提供了一个接口. 路径名由斜线分隔的一个或者多个文件名组成的序列: 以斜线开头的路径名称为绝对路径名 以非斜线开头的路径名称为相对路径名 文件系统根的名字 / 是一个特殊的绝对路径名.它不包含任何其他的字符. 查看UNIX系统ls命令的 man帮助手册:man 1 ls或者 man -s1 ls.

自学: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基础知识)

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

第一章 UNIX 基础知识

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