zoukankan      html  css  js  c++  java
  • APUE学习笔记:第一章 UNUX基础知识

    1.2 UNIX体系结构

    从严格意义上,可将操作系统定义为一种软件(内核),它控制计算机硬件资源,提供程序运行环境。内核的接口被称为系统调用。公用函数库构建在系统调用接口之上,应用软件即可使用公用函数库,也可使用系统调用。shell是一种特殊的应用程序,它为运行其他应用程序提供了一个接口

    从广义上,操作系统包括了内核和一些其他软件,这些软件使得计算机能够发挥作用,并给予计算机以独有的特性(软件包括系统实用程序,应用软件,shell以及公用函数库等)

    1.3  shell

    shell是一个命令行解释器,它读取用户输入,然后执行命令。用户通常用终端(交互式shell),有时则通过文件(shell script)向shell进行输入

    UNIX系统常见shell:

                            名称                 路径

            Boune shell:       /bin/sh

            Bourne-again shell:  /bin/bash

            C shell:        /bin/csh

            Korn shell:      /bin/ksh

            TENEX C shell:    /bin/tcsh  

    C shell其控制流类似于C语言,它支持Bourne shell没有的某些特色功能,例如作业控制、历史记忆机制以及命令行编辑等

    Korn shell它与Bourne shell向上兼容,并具有使C shell广泛得到应用的一些特色功能,包括作业控制以及命令行编辑

    Bourne-again shell是GNUshell,所有linux都提供这种shell,它被设计成遵循POSIX的,同时也保留了与Bourne shell的兼容性。它支持C shell和Korn shell两者的特色功能

    TENEX C shell 是C shell的加强版本。它从TENEX操作系统借鉴了很多特色,例如命令完备。TENEX C shell在C shell的基础上增加了很多特征,常被用来替换C shell

    注:linux默认shell是Bourne-again shell.事实上,/bin/sh将链接到/bin/bash.FreeBSD 和Mac OS X的默认用户shell是TENEX C shell,但是因为使用C shell编程语言极其困难,所以它们使用Bourne shell编写用于管理方面的shell脚本

    1.4文件和目录

    1.文件系统

    UNIX文件系统是目录和文件组成的一种层次结构,目录的起点称为根(root),其名字是一个字符/。文件属性是指文件类型(是普通文件还是目录)、文件大小、文件所有者、文件权限以及文件最后的修改时间等。

    2.文件名

    目录中的各个名字称为文件名。不能出现在文件名中的字符只有斜线(/)和空操作符(null)两个。

    创建新目录时会自动创建两个文件名:.(当前目录),..(父目录)

    3.路径名

    以斜线开头的路径名称称为绝对路径名,否则称为相对路径名

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

     1 #include"apue.h"
     2 #include<dirent.h>
     3 int main(int argc,char *argv[])    //argc表示参数个数;argv表示参数内容
     4 {
     5     DIR *dp;
     6     struct dirent *dirp;      
     7     if(argc!=2)
     8     err_quit("usage:ls directory_name");
     9     if((dp=opendir(argv[1]))==NULL)  //opendir函数返回指向DIR结构的指针
    10     err_sys("can't open%s",argv[1]);
    11     while((dirp=readdir(dp))!=NULL)  //readdir返回一个指向dirent结构的指针
    12     printf("%s
    ",dirp->d_name);
    13     closedir(dp);
    14    exit(0);
    15 }

    这段代码类似于ls命令,不过这段代码只打印一个目录中各个文件的名字,不显示其他信息

    编译方法:$ cc xxx.c  编译

                  $ ./a.out  运行   

    (可能很多初学者在编译这段代码时会出现找不到apue.h,这里我发个配置apue.h头文件的链接 http://www.linuxidc.com/Linux/2013-01/77686.htm)

    1.5输入与输出

    1.文件描述符

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

    3.不用缓冲的I/O

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

    程序清单1_2 将标准输入复制到标准输出

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


    4.标准I/O

    标准I/O函数提供一种对不用缓冲I/O函数的带缓冲的接口。使用标准I/O函数可以无需担心如何选取最佳的缓冲区大小,例如1_2中BUFFSIZE常量的大小。使用标准I/O函数的另一个优点是简化了对输入行的处理。例如,fgets函数读一完整的行,而read函数读指定字节数。(printf函数便是标准I/O函数)

    实例:1_3 用标准I/O将标准输入复制到标准输出

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

    附:无缓冲I/O操作和标准I/O操作的区别 http://blog.csdn.net/cowbane/article/details/6630298

    1.6程序和进程

    1.程序是存放在磁盘上,处于某个目录中的一个可执行文件。使用6个exec函数中的一个由内核将程序读入存储器,并使其执行

    2.进程和进程ID

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

    实例:1_4 打印进程ID

    1 #include"apue.h"
    2 int main()
    3 {
    4     printf("hello world from process ID %d
    ",getpid());
    5     exit(0);
    6 }

    此程序运行时,它调用函数getpid得到其进程ID

    3.进程控制

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

    实例: 1_5 从标准输入读命令并执行(类shell程序)

     1 #include"apue.h"
     2 #include<sys/wait.h>
     3 4 
     5 int main(void)
     6 {
     7     char buf[MAXLINE];
     8     pid_t pid;    
     9     int status;
    
    13     printf("%% ");
    14     while(fgets(buf,MAXLINE,stdin)!=NULL){
    15     if(buf[strlen(buf)-1]=='
    ')
    16     buf[strlen(buf)-1]=0;             //用null替换换行符
    17     if((pid=fork())<0){            //fork向父进程返回新子进程的进程ID(非负),对子进程则返回0;所以说它被调用一次,返回两次
    18     err_sys("fork error");
    19     }
    20     else if(pid==0){          
    21     execlp(buf,buf,(char *)0);    //execlp执行从标准输入读入的命令。fork和跟随其后的exec两者的组合是某些操作系统所称的产生(spawn)一个新进程
    22     err_ret("couldn't execute:%s",buf);
    23     exit(127);
    24     }
    25     if((pid=waitpid(pid,&status,0))<0)    //waitpid函数返回子进程的终止状态
    26     err_sys("waitpid error");
    27     printf("%% ");
    28     }
    29     exit(0);
    30 }
    

    该程序的主要限制是不能向所执行的命令传递参数,例如不能指定要列表的目录名,只能对工作目录执行ls命令

    4.线程和线程ID

    在一个进程内的所有线程共享同一地址空间、文件描述符、栈以及进程相关的属性。线程ID只在它所属进程内起作用。一个进程中的线程ID在另一个进程中并无意义。

    1.7出错处理

    当unix函数出错时,常常返回一个负值,而且整型变量errno通常被设置为含有附加信息的一个值。例如,open函数如成功执行则返回一个非负文件描述符,如出错则返回-1。

    实例:1_6 示例strerror和perror两个出错函数的使用方法

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

    1.8用户标识

    用户ID 和组ID

    示例:1_7 打印用户ID和组ID

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

    1.9信号

    信号是通知进程已发生某种情况的一种技术。

    进程处理信号有三种选择:a.忽略该信号

                b.按系统默认方式处理。对于除以0的情况,系统默认是终止该进程

                c.提供一个函数,信号发生时则调用该函数,这被称为捕捉该信号。使用这种方式,我们只要提供自编的函数就将能知道什么时候产生了信号,并按所希望             的方式处理它

    实例:1_8 从标准输入读命令并执行(比1_5多了信号处理)

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

    1.10时间值

    UNIX系统使用三个进程时间值:时钟时间,用户cpu时间,系统cpu时间

    时钟时间又称为墙上时钟时间(wall clock time)。它是进程运行的时间总量,其值与系统中跟同时运行的进程数有关。

    用户CPU时间是执行用户指令所用的时间。

    系统cpu时间是为该进程执行内核程序所经历的时间

    例如:每当一个进程执行一个系统服务时,如read或write,则在内核内执行该服务所花费的时间就计入该进程的系统cpu时间。用户cpu时间和系统cpu时间之和常被称为cpu时间

    取得任意进程的时钟时间,用户时间,和系统时间:$cd /usr/include;time -p grep _POSIX_SOURCE */*.h > /dev/null

  • 相关阅读:
    python中的map,fliter,reduce用法
    python中的函数参数传递
    python中的全局变量和局部变量
    python中的函数定义
    python中的eval()和exec()函数
    kafka手动提交,丢失数据
    02-基本概念
    01-接触kafka
    (8)适配模式--结构性
    java内存划分
  • 原文地址:https://www.cnblogs.com/wbingeek/p/3835279.html
Copyright © 2011-2022 走看看