Unix环境高级编程阅读之一——Unix\Linux基础知识

所有的操作系统都为它们所运行的程序提供服务。典型的服务包括:执行新程序、打开文件、读文件、分配存储区以及获得当前时间等。
UNIX体系结构示意图

操作系统 是用来控制计算机的硬件资源,提供程序运行环境。
其中,内核的接口被称为是系统调用,公用函数库构建在系统调用之上,应用程序既可以使用公共函数库,也可以使用系统调用。shell是一个特殊的应用程序,它为其他应用程序提供了一个接口。

在目录/etc/passwd文件中可以查看用户的登录项信息,在口令文件中,每个登录项由七个以冒号分隔的字段组成,分别表示登录名、加密口令、数字用户ID、数字组ID、注释字段、起始目录以及shell程序。

shell是一个命令行解释器,它读取用户输入,然后执行命令。

Unix文件系统
起点是/。
目录是一个包含目录项的文件。每个目录项都包含一个文件名,同时还包含该文件属性的信息。文件属性是指文件类型、文件大小、文件所有者、文件权限以及文件的最后修改时间。
POSIX.1推荐奖文件名限制在以下的字符集之内:字母(a~z,A~Z)、数字(0~9)、句点(.)、短横线(-)、下划线(_)。
创建新目录时,会自动创建两个目录“.”和“..”,分别指向当前目录和父目录。在最高层次的目录中,二者含义相同,均指向当前目录。

dirent.h
是POSIX.1标准定义的unix类目录操作的头文件,包含了许多UNIX 系统服务 的函数原型,例如opendir函数、readdir函数.
#include <dirent.h>
是POSIX.1标准定义的unix类目录操作的头文件,包含了许多UNIX 系统服务 的函数原型,例如opendir函数、readdir函数.
opendir函数:
DIR *opendir(const char *pathname);返回值:若成功则返回 指针 ,若出错则返回NULL。
struct dirent *readdir(DIR *dp); 返回值:若成功则返回指针,若在目录结尾或出错则返回NULL。

自己实现的一个简单的ls工具,代码如下:

在Unix中,一般来说,返回0表示执行成功,而1到255表示执行的任务出错。

Unix中的输入输出操作
(1)文件描述符:一个小的非负整数,内核用以标识一个正在访问的文件。
(2)标准输入重定向、标准输出重定向、标准错误重定向。STDIN_FILENO和STDOUT_FILENO定义在<unistd.h>中,它们指定了标准输入和标准输出的两个文件描述符。在POSIX标准中,它们分别是0和1。
(3)不带缓冲的IO:函数open、read、write、lseek以及close提供了不带缓冲的I/O。这些函数都使用文件描述符。
read函数返回读取的字节数。当文件到达尾端时,read返回0;当发生读取错误,read返回-1。注意,Unix的系统函数出错时,大多返回-1。
(4)标准输入输出函数:标准输入输出函数为那些不带缓冲的输入输出函数提供了一个带缓冲的接口。无须担心最佳的缓冲区大小的选择,并且简化了对输入行的处理。如:getc、putc、fgets函数、printf函数。头文件<stdio.h>。

Unix的程序与进程
程序是一个存储在磁盘上某个目录中的可执行文件。内核使用exec(七个函数中的一个),将程序读入内存,并执行程序。使用getpid这个函数可以获取当前运行的进程的id号,它返回的是一个pid_t类型的数据,可以将其强制转换为long类型。
有关于进程控制的函数:fork、exec、waitpid。
①其中exec有七个变体。
②fork函数对父进程返回子进程的pid(一个非负整数),对子进程返回0。所以说,fork被调用一次,但是返回两次(父与子)。
③waitpid函数可以指定要等待的进程id。它将返回子进程的终止状态(status变量)。

ctrl+D是一个控制字符,表示默认的文件结束符。

Unix的线程和线程ID
一个进程内的所有线程共享同一地址空间、文件描述符、栈以及与进程相关的属性。因为它们能访问同一存储区,所以在个线程访问共享数据时,需采取同步措施。线程也有ID,但仅在本进程内有用。

Unix的出错信息
出错通常会返回一个负值。errno这个整型变量被设置为具有特定信息的值。有大约15种。<errno.h>重定义。
在Unix手册intro(2)中也列出了所有这些出错的常量。在Linux种,定义在errno(3)手册中。使用man 3 errno命令可以查看。
POSIX和ISO C将errno定义为一个符号,它扩展成为一个可修改的整型左值。
对于errno需要注意的是,(1)如果没有出错,该值不会被清除;仅当函数返回值指明出错时,才检验其值;(2)没有任何函数将errno设置为0,<errno.h>重所定义的所有常量都不为0。
C标准中定义了两个函数用于打印出错信息。
(1)<string.h>中,char *strerror(int errnum);它将errnum映射为一个出错字符串,并返回其指针。
(2)<stdio.h>中,void perror(const char *msg);perror对应当前的errno,输出一条出错信息。首先输出msg指定的字符串,然后输出一个冒号,之后就是出错信息。
出错分类:
(1)致命性出错:无法执行恢复动作,最多就是想屏幕打印出一条出错信息或者将一条出错信息写入日志文件中。
(2)非致命性出错:EAGAIN(资源暂时不可用)、ENFILE(系统当前打开过多文件)、ENOBUFS(没有缓冲区)、ENOLCK(没有锁)、ENOSPC(设备中空间不足)、EWOULDBLOCK(操作将被阻塞),有时,ENOMEM(空间不足)也是非致命性出错。当EBUSY(设备或资源正忙)指明共享资源正在使用时,也可以将其作为一个非致命性的出错处理。当EINTR(中断函数调用)中断一个慢速系统调用时,可将它作为非致命性出错处理。 对于非致命性出错的典型恢复操作是延迟一段时间,然后重试。

Unix用户标识
(1)用户ID。ID为0的用户是根用户或称是超级用户。使用<unistd.h>中的getuid函数可以获取用户id。
(2)组ID。/etc/group文件中将组名应设为数值的组ID。这种机制允许同组的各个成员之间共享资源。使用<unistd.h>中的getgid函数可以获取组id。
(3)附属组ID。允许一个用户属于多至16个其他的组。

Unix信号
用于通知进程发生了某种情况。例如,SIGFPE是浮点异常,当除数为零的时候会被发送。
Unix进程有三种处理信号的方式:
(1)忽略信号。
(2)按系统默认方式处理。
(3)提供一个函数,当信号发生时,调用这个函数。这被称为捕捉信号。

终端键盘有两种 产生信号 的方法:中断键(ctrl+C或Delete键)和退出键(ctrl+\键)。还有一种方式,调用kill函数,要求是进程的所有者或是root用户。

为了捕捉信号,程序需要调用signal函数。

Unix时间值
Unix系统使用两种不同的时间值:
(1)日历时间。系统基本类型time_t用来保存这个时间值。
(2)进程时间。系统基本类型clock_t用来保存这个时间值。使用sysconf这个函数获取时钟嘀嗒。
Unix为一个进程维护了3个进程的时间值:
①时钟时间,进程运行的时间总量,其值与系统中同时运行的进程数有关。
②用户CPU时间:执行用户指令所用的时间量。
③系统CPU时间:为该进程执行内核程序所需的时间量。

系统调用和库函数
系统调用时操作系统提供的多种服务的入口点,由此程序向内核请求服务。
Unix所使用的技术是为每个系统调用在标准C库中设置一个具有同样名字的函数。用户进程用标准C调用序列来调用这些函数,然后,函数又用系统所要求的技术调用相应的内核服务。
注意区分系统调用和库函数
(1)系统调用和库函数从实现者的角度来看,具有根本的区别。但从用户角度,其区别并不重要。有些库函数可能会调用一个或多个系统调用,但他们并不是内核的入口点。有些库函数并不使用任何内核的系统调用。
举例:malloc库函数是以特定方式进行存储空间分配的函数。它在根本上,其实是调用了系统调用sbrk,这个系统调用是按指定字节数增加或减少进程的地址空间。两者的职责不同,内核中的系统调用分配一个空间给进程,而库函数malloc砸在用户层次上管理这个空间。
(2)系统调用通常提供一种最小接口,而库函数通常提供比较复杂的功能。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值