zoukankan      html  css  js  c++  java
  • Unix System Overview

    一.Unix 体系结构

    由上图可以看出,内核居于最里层,Shell,Libary routines,以及Application通过系统调用(system calls)访问内核提供的功能。注意系统调用与函数调用的关系,两者不是一个东西。应用程序可以通过Shell和库访问内核功能,也可以直接通过系统调用访问内核。

    二.登录

    1.登录

    我们使用用户名和密码登录Unix系统,系统会在/etc/passwd文件中校验我们的用户名,在/etc/shadow中校验密码。/etc/passwd文件内容格式如下:

    root:x:0:0:root:/root:/bin/bash

    其中各项用:隔开,分别代表:用户名,密码保存位置,UserID,GroupID,注释,家目录,使用的shell.

    /etc/shadow文件内容格式如下:

    root:x:16097:0:99999:7::::

    各项用:分开,分别代表:用户名,加密密码,上次更改密码的时间,最短密码期限等

    2.shell

    使用的shell 由登录文件的最后一项决定,一般是/bin/bash,常见的shell除了bash ,还有C Shell,B shell,K shell,T Shell


    三.文件和目录

    1.文件系统

    Unix系统文件结构由目录与文件构成的树构成,/为根目录。目录是包含目录项的文件,目录项是由包含文件名以及描述文件属性的结构组成。文件属性一般有文件的所有者,文件的访问权限,文件的大小,存储位置等。

    2.文件名

    文件名由字母,_,数字组成,/和NULL不可出现在文件名中。.与..在创建任何目录的时候自动创建,分别代表当前目录以及父目录。

    3.路径名

    由/开始并由/分隔开来的多个文件名组成的字符串称为路径名,比如/root/test,路径分为绝对路径和相对路径。绝对路径指从根目录/出发一直到访问目的目录,否则即为相对路径。

    下面的代码实现一个简单的ls

    <span style="font-size:18px;"><span style="font-size:18px;">/*************************************************************************
    	> File Name: ls.c
    	> Author: CodingPeasant
    	> Mail: 1612853779@qq.com
    	> Created Time: Mon 11 Aug 2014 06:10:09 AM PDT
     ************************************************************************/
    
    #include<stdio.h>
    #include <stdlib.h>
    #include <dirent.h>
    
    int main(int argc,char * argv[])
    {
    	DIR* dp;
    	struct dirent  *dirp;
    
    	if(argc != 2)
    	{
    		printf("usage:myls directory_name");
    		exit(-1);
    	}
    
    	if( (dp = opendir(argv[1])) == NULL )
    	{
    		printf("can not open %s",argv[1]);
    		exit(-1);
    	}
    	while((dirp = readdir(dp)) != NULL)
    	{
    		printf("%s\n",dirp->d_name);
    	}
    
    	closedir(dp);
    
    	return 0;
    }
    </span></span>

    3.工作目录

    工作目录也叫当前工作目录,是进程的一个属性,进程可以使用chdir系统调用更改自己的工作目录。

    4.家目录

    我们登录后的第一个目录就是当前用户的家目录,家目录由登录文件/etc/passwd最后一项决定。


    四.输入与输出

    1.文件描述符:内核用于标记被进程访问的文件的的小正整数,由open()或者create()返回,用于其他文件访问的参数。

    2.Shell在执行新程序的时候,打开标准输入,标准输出,标准出错输出,默认三者都指向终端文件。

    3.非缓冲IO:所有IO操作都在内核空间中完成,open,read,write,seek,close是基本操作,这几个系统调用都和文件描述符(file descibe)相关联。

    下面是一个拷贝到小程序:

    <span style="font-size:18px;">/*************************************************************************
      > File Name: cp.c
      > Author: CodingPeasant
      > Mail: 1612853779@qq.com
      > Created Time: Tue 12 Aug 2014 06:27:16 AM PDT
     ************************************************************************/
    
    #include<stdio.h>
    #include<unistd.h>
    #include<stdlib.h>
    
    #define BUFFSIZE 4096
    
    int main()
    {
    	int n;
    	char buf[BUFFSIZE];
    
    	while( ( n = read(STDIN_FILENO,buf,BUFFSIZE)) > 0 )
    	{
    		if(write(STDOUT_FILENO,buf,n)!= n)
    		{
    			printf("write error");
    			exit(-1);
    		}
    	}
    
    	if (n < 0)
    	{
    		printf("read error");
    		exit(-1);
    	}
    	exit(0);
    }
    </span>


    假设生成的文件为mycp,则执行mycp < input_file,输入为input_file,输出为终端,出错输出也为终端。

    执行mycp <input_file >out_file 则复制input_file内容到out_file。

    4.标准IO:提供带有缓冲机制的IO访问函数,不需要自己管理缓冲区大小。

    五.进程

    1.程序和进程:程序指存在磁盘上的可执行文件,是静态的行为。当程序被内核以exec函数执行的时候,就变成了进程,进程是动态行为。

    2.进程ID:每个进程都有一个非负数标识,叫做进程ID。

    下面的小程序获取进程ID:

    <span style="font-size:18px;">/*************************************************************************
    	> File Name: pid.c
    	> Author: CodingPeasant
    	> Mail: 1612853779@qq.com
    	> Created Time: Tue 12 Aug 2014 06:59:38 AM PDT
     ************************************************************************/
    
    #include<stdio.h>
    #include<unistd.h>
    #include<sys/types.h>
    
    int main()
    {
    	pid_t pid;
    
    	printf("current process id:%ld\n",(long)getpid());
    
    	return 0;
    }
    </span>


    3.进程管理:fork创建子进程,exec函数族执行新程序,waitpid,wait进行子进程善后处理。下面是一个简易版shell:

    <span style="font-size:18px;">/*************************************************************************
    	> File Name: shell.c
    	> Author: CodingPeasant
    	> Mail: 1612853779@qq.com
    	> Created Time: Tue 12 Aug 2014 07:12:58 AM PDT
     ************************************************************************/
    
    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include<sys/wait.h>
    #include<unistd.h>
    
    #define MAXLINE 100
    int main(int argc,char* argv[])
    {
    	char buf[MAXLINE];
    	pid_t pid;
    	int status;
    
    	printf("%%");
    	while(fgets(buf,MAXLINE,stdin)!= NULL)
    	{
    		if(buf[strlen(buf)-1] == '\n')
    		{
    			buf[strlen(buf)-1] = 0; /*replace \n to NULL*/
    		}
    
    		if((pid = fork()) < 0)
    		{
    			printf("fork error\n");
    			exit(-1);
    		}else if(pid == 0)//child process
    		{
    			execlp(buf,buf,(char*)0);//exec new progromme
    			printf("can not execute :%s",buf);
    			exit(127);
    		}
    
    		//parent
    		if((pid = waitpid(pid,&status,0)) < 0)
    		{
    			printf("waitpid error");
    			exit(-1);
    		}
    		printf("%%");
    	}
    
    }
    </span>


    关于程序的几点说明:

    1.因为exec函数最后一个参数需要(char*)0,所以将读入的字符串的newline符号改为NULL

    2.execlp第一个参数为文件名,系统会在环境变量中查找该文件,如果文件不是可执行文件,尝试用shell执行之。如果文件没找到报错

    3.waitpid进行子进程资源回收以及执行状态获取。


    线程:是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。进程中的所有线程共享进程的地址空间,文件描述符,栈以及其他进程属性。

    线程ID:用于唯一标识一个线程,只在同一个进程中有意义。


    六.错误处理

    1.在Unix中一般函数调用出错返回值小于0,并且设置errno,用了表示发生了什么错误。

    2.<errno.h> 定义了错误号的宏

    3.通过char* strerror(int errnum);可以返回errnum对应的字符串标识

    4.通过void perror(const char* msg);打印提示信息msg:error message


    七.用户标识

    1.User ID:由root分配用于系统唯一标识一个用户的数字,我们不可以改变。系统使用UserID测试我们是否可以访问相关资源。

    2.Group ID:由root分配用于系统唯一标识一个组的数字。

    3.附加组ID(Supplementary Group IDs):一个用户可以属于其他 组,用附加组ID表示这些组。

    获取UserID 和 Group ID的小程序:

    <span style="font-size:18px;">#include <sys/types.h>
    #include <unistd.h>
    #include <stdio.h>
    
    int main()
    {
        printf("uid:%d,gid:%d",getuid(),getgid());
        exit(0);
    }</span>


    八.信号

    1.信号:用来通知进程某些条件发生的一种机制

    2.对信号的处理方式:(1)忽略信号 (2)按照默认行为处理 (2)设置信号处理函数

    3.增加了信号处理的简单shell:

    <span style="font-size:18px;">/*************************************************************************
      > File Name: shell.c
      > Author: CodingPeasant
      > Mail: 1612853779@qq.com
      > Created Time: Tue 12 Aug 2014 07:12:58 AM PDT
     ************************************************************************/
    
    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include<sys/wait.h>
    #include<unistd.h>
    #include<signal.h>
    
    #define MAXLINE 100
    
    //deal with intrupt signal
    static void sig_int(int);
    
    int main(int argc,char* argv[])
    {
        char buf[MAXLINE];
        pid_t pid;
        int status;
    
        if(signal(SIGINT,sig_int) == SIG_ERR)
        {
            printf("signal error");
            return -1;
        }
        printf("%%");
        while(fgets(buf,MAXLINE,stdin)!= NULL)
        {
            if(buf[strlen(buf)-1] == '\n')
            {
                buf[strlen(buf)-1] = 0; /*replace \n to NULL*/
            }
    
            if((pid = fork()) < 0)
            {
                printf("fork error\n");
                exit(-1);
            }else if(pid == 0)//child process
            {
                execlp(buf,buf,(char*)0);//exec new progromme
                printf("can not execute :%s",buf);
                exit(127);
            }
    
            //parent
            if((pid = waitpid(pid,&status,0)) < 0)
            {
                printf("waitpid error");
                exit(-1);
            }
            printf("%%");
        }
    
    }
    
    void sig_int(int signo)
    {
        //just print signo
        printf("interrupt:%d\n",signo);
    }
    </span>


    九.时间值

    1.时间值分为:(1)日历时间,用time_t 结构表示,表示从1970 -1-1 00:00 到当前的秒数 (2)进程时间,用clock_t 结构标识,标识进程执行花了多少时钟

    2.进程时间通常用三种值来衡量:(1)User CPU time :执行用户指令花费的时钟数(2)Sytem CPU time :执行系统指令花费的时钟数(3) clock time:进程执行花了多少时钟,受到其他进程的影响,通常指单一进程花费的时间


    .系统调用和库函数调用

    1.进程执行分为用户态和内核态

    2.系统调用和库函数调用区别:

    函数库调用

    系统调用

    在所有的ANSI C编译器版本中,C库函数是相同的

    各个操作系统的系统调用是不同的

    它调用函数库中的一段程序(或函数)

    它调用系统内核的服务

    与用户程序相联系

    是操作系统的一个入口点

    在用户地址空间执行

    在内核地址空间执行

    它的运行时间属于用户时间

    它的运行时间属于系统时间

    属于过程调用,调用开销较小

    需要在用户空间和内核上下文环境间切换,开销较大

    C函数库libc中有大约300个函数

    UNIX中大约有90个系统调用

    典型的C函数库调用:system fprintf malloc

    典型的系统调用:chdir fork write brk



  • 相关阅读:
    如何保证 Redis 缓存与数据库双写一致性?
    如何合理地估算线程池大小?
    不用装工具,一条 Linux 命令就能实现文件上传下载!
    看了 Google 大神 Jeff Dean 的传说,我拜服了~
    div设置水平垂直居中
    "起用"与"启用"
    徇私舞弊
    精选排比金句20例
    一笔画图推
    一笔画
  • 原文地址:https://www.cnblogs.com/xiaofeifei/p/3982213.html
Copyright © 2011-2022 走看看