Unix基础知识

一,输入和输出

1.1 文件描述符:

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

1.2 标准输入 标准输出 标准错误:

每当运行一个新程序时,所有的shell都为其打开3个文件描述符,即标准输入、标准输出和标准错误。这三个描述符都链接至终端。

在头文件#include <unistd.h>中,定义了三个常量以表示标准输入、标准输出、标准错误。

/* Standard file descriptors.  */
#define	STDIN_FILENO	0	/* Standard input.  */
#define	STDOUT_FILENO	1	/* Standard output.  */
#define	STDERR_FILENO	2	/* Standard error output.  */
# 使其中任何一个或所有这三个描述符都能重新定向到某个文件
ls > file.list # 将标准输出重定向到文件file.list

1.3 不带缓冲的I/O:

函数open、read、write、lseek、close等系统调用提供了不带缓冲的I/O。

ssize_t read(int fd, void *buf, size_t count);

1.4 带缓冲的I/O:

标准I/O库函数是带缓冲的函数,无需担心如何选取缓冲区的大小。

二,程序和进程

2.1 程序

程序是一个存储在磁盘上某个目录的可执行文件。内核使用exec函数将程序读入内存并执行程序

2.2 进程和进程ID

程序的一次执行实例称为进程。UNIX系统为每个进程都有一个唯一的数字标识符,即进程ID(PID),一个非负整数。在进程中可以通过getpid()系统调用获取自身PID。

2.3 线程和线程ID

一个进程内的所有线程共享同一地址空间、文件描述符、栈以及与进程相关的属性。

线程也用ID标识,但是线程ID只在它所属的进程内起作用。一个进程中的线程ID在另一个进程中没有意义。

三,出错处理

当UNIX系统调用出错时,通常会返回负值(有些返回的是空指针等),并且变量errno被设置为具有特定信息的值

errno以前的定义是:

extern int errno;

但是在支持线程的环境中,多个线程共享进程地址空间,每个线程都有属于它自己的局部errno,以避免一个线程干扰另一个线程。因此errno定义为

extern int *__errno_location (void);
# define errno (*__errno_location ())

对于errno需要注意两点:

  • 如果没有出错,errno值不会被例程清除。因此仅当函数返回值出错时,再检验errno值

  • 任何函数都不会将errno设置为0

C标准提供两个函数以打印出错信息

  • perror函数:
#include <stdio.h>
void perror (const char *msg); 

先在标准错误上输出错误信息msg,然后是一个冒号一个空格,接着是errno对应的错误信息,然后换行符

  • strerror函数:
#include <string.h>
char *strerror (int errnum);

将errnum(通常就是errno)对应的出错信息字符串返回。

#include "apue.h"
#include <errno.h>

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

四,用户标识

4.1 用户ID

在口令文件的登录项中用户ID是一个数值,用来向系统标识不同的用户

用户ID为0的用户为根用户(root)或超级用户(superuser),可以在口令文件中看到一个登录项的用户名是root。

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

这种用户的特权为超级用户特权,如果一个进程有超级用户特权,那么大多数文件权限检查都不再进行。

4.2 组ID

口令文件的登录项也包含组ID,也是一个数值。在口令文件中,有多个登录项拥有相同的组ID。

组ID用于将若干用户分配到不同的项目和部门中去,允许同组的各个成员之间共享资源(如文件)。比如可以设置文件权限为组内所有用户可以访问,组外用户不能访问。

组文件:*将组名映射为数值的组ID,通常是*/etc/group

$ cat /etc/group
> root:x:0:
> daemon:x:1:

对于磁盘上的每个文件,文件系统通常存储该文件所有者的用户ID和组ID,而不是用户名和组名。这是因为存储这两个ID只需要4个字节(假定每个ID以双字节整形值存放),而如果使用完整用户名和组名,需要更多的字节(需要更多磁盘空间)。另外在检验权限时,字符串比较与整数比较相比更慢

但对于用户而言使用用户名和组名更方便,因此使用口令文件包含用户名和用户ID的映射,组文件包含组名和组ID的映射。比如ls -l命令就使用口令文件将用户ID映射为用户名从而打印出文件所有者的用户名。

进程可以使用getuid()getgid()获取用户ID与组ID。

组文件将组名映射为数值的组ID。组文件通常是/etc/group

#include "apue.h"
int main(void){
    printf("uid = %d,gid = %d\n",getuid(),getgid());
    exit(0);
}
4.3 附属组ID

大多数UNIX系统还允许一个用户属于另外一些组。允许一个用户属于最多16个其他的组。

可以通过etc/group中列有指定用户作为其成员的前16个记录项即为该用户的附属组。

adm:x:4:syslog # ID为4的组是syslog用户的附属组

/etc/group文件的每个记录项字段意义:

组名:加密口令:组ID:组中的附加用户

五, 信号

用于通知进程发生了某种情况。如执行除0操作,则将SIGFPE(浮点异常)信号发送给该进程。

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

  • 忽略信号(不推荐)
  • 按系统默认方式执行,比如对于除0操作,系统默认方式是终止进程
  • 提供信号处理函数,信号发生时调用该函数,称之为捕捉该信号。

六, 时间值

UNIX使用两种不同的时间值

6.1 日历时间

自1970年1月1日00:00:00起到某时刻的秒数,通过time_t类型保存这种时间值。

7.2 进程时间

用于表示进程使用CPU时间资源。进程时间以时钟滴答计算,每秒钟曾经取为50,60,100个时钟滴答。通过clock_t类型保存这种时间值。

UNIX系统为每个系统维护了三个进程时间值

  • 时钟时间:

    进程运行的总时间。时钟时间 = 阻塞时间 + 就绪时间 + 运行时间。

  • 用户CPU时间:

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

  • 系统CPU时间:

    进程获得了CPU资源以后,在内核态的执行时间

CPU时间 = 用户CPU时间 + 系统CPU时间

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

在这里插入图片描述

  • 27
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值