Unix基础
来源:互联网 发布:js处理遍历json数据 编辑:程序博客网 时间:2024/04/28 10:51
概述
操作系统的任务是为其上运行的程序服务:包括运行、打开文件、读文件、分配内存以及时间获取。
架构
定义:
In a strict sense, an operating system can be defined as the software that controls the hardware resources of the computer and provides an environment under which programs can run.
UNIX的体系结构
由内而外:
- 内核 其接口被称为系统调用(System call)。
- shell 特殊的应用程序,为其他应用程序提供接口。
- 库函数 在系统调用接口基础上的函数库。
- 应用 就是应用。。
登录
登录方式
系统根据输入的用户名去/etc/passwd
目录下检索用户名并找到对应的密码文件进行密码匹配。
密码文件长这样:
sar:x:205:105:Stephen Rago:/home/sar:/bin/ksh
上述对应各字段值类型:
登录名:加密的密码:用户ID:组ID:注释域:起始:shell程序
shell
shell是一个命令解释器,与用户进行交互。
文件与目录
- 文件系统 树状层级结构
- 文件名
- 路径名 创建目录时候自动生成当前目录
.
和父目录..
。 - 工作目录 每个进程都有一个工作目录
- 起始目录
栗子:ls简要实现
#include "apue.h"#include <dirent.h>int main (int argc, char *argv[]) { DIR *dp; struct dirent *dirp; // 输入参数不为2, 暗示使用方法不对 if (argc != 2) { err_quit("usage: ls directory_name"); } // 打开指定目录失败 if ((dp = opendir(argv[1])) == NULL) { err_sys("can't not open %s", argv[1]); } // 遍历dp文件夹 打印内部文件的文件名 while ((dirp = readdir(dp)) != NULL) { printf("%s\n", dirp->d_name); } // 关闭文件夹句柄 && 退出程序 closedir(dp); exit(0);}
这里可能遇到一个apue.3e的编译问题,解决方案戳这里。
命令行编译执行结果如下:
输入与输出
文件描述符 (file descriptor)
通常是一个小的非负整数,内核用它标识一个特定进程访问的文件。
标准输入 标准输出 标准错误
一般来说,所有派系的shell都会为程序打开标准输入、标准输出、标准错误三个文件描述符。并且这三个文件描述符都能重定向到某个文件。
ls > file.list
非缓冲的I/O
非缓冲函数如:open, read, write, lseek, close
。这些函数都与文件描述符协作。
举个栗子:从标准输入读写入标准输出
#include <stdio.h>#include <apue.h>#define BUFFSIZE 4096int main(void) { int n; char buf[BUFFSIZE]; // 头文件<unistd.h>中包含了`STDIN_FILENO`与`STDOUT_FILENO`两个常量 while ((n = (int)read(STDIN_FILENO, buf, BUFFSIZE)) > 0) { if (write(STDOUT_FILENO, buf, n) != n) { err_sys("write error"); } if (n < 0) { err_sys("read error"); } } exit(0);}
命令运行结果截图:
标准I/O
标准I/O函数提供一种对不用缓冲I/O函数的带缓冲接口。 无脑说就是不用设置缓冲区大小。比如fgets函数读完一行的长度而read函数需要制定读入的字节数。
我们最熟悉得标准I/O是printf
。。。
举个栗子: 用标准I/O将标准输入复制到标准输出
#include <stdio.h>#include <apue.h>int main(void) { int c; // 头文件<unistd.h>中包含了`STDIN_FILENO`与`STDOUT_FILENO`两个常量 while ((c = getc(stdin)) != EOF) { if (putc(c, stdout) == EOF) { err_sys("output error"); } if (ferror(stdin)) { err_sys("input error"); } } exit(0);}
运行结果略。。
程序和进程
程序
程序是放在磁盘上的。
进程和进程ID
程序执行的实例叫做进程。每个进程都有自己的唯一标识符PID。
栗子:打印进程ID
int main(void) { printf("hello world from process ID %d\n", getpid()); exit(0);}
运行结果:
进程控制
进程控制主要函数有:fork、exec、waitpid
举个栗子:
#include <stdio.h>#include <sys/wait.h>#include <apue.h>int main(void) { 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; } if ((pid = fork()) < 0) { err_sys("fork error"); } else if (pid == 0) { execlp(buf, buf, (char *)0); err_ret("couldn't execute: %s", buf); exit(127); } if ((pid = waitpid(pid, &status, 0)) < 0) { err_sys("watipid error"); } printf("%% "); } exit(0);}
运行结果:
线程和线程ID
通常一个进程只有一个控制线程,同一时刻只能执行一组机器指令。
在同一个进程内得线程共享同一个地址空间、文件描述符、栈以及进程相关属性。
因为共享资源的关系,所以这里有个线程安全的概念。
与进程相同,线程也用ID标识。线程ID只在进程中起作用。出了进程就没有意义了。
出错处理
UNIX函数出错的时候通常返回一个负值,用errno
表示错误得种类。某些函数不返回负值而是使用另外一种约定,比如返回一个只想对象的指针的大多数函数,出错时候返回null指针。
使用errno的两条规则:
- 如果没有出错,则errno值不会被例行清除。只有当函数返回值错误的时候才去检查其值。
- 没有函数会将
errno
值设置为0,在<errno.h>中定义的所有常量都不为0。
标准C钟定义了下面两个方程来实现打印错误消息。
char *strerror(int errnum);void perror(const char *msg);
第一个函数表明根据errno找到错误信息字符串指针,第二个函数表明根据指针,打印出错误信息。
举个栗子:
#include <string.h>#include <errno.h>int main(int argc, char *argv[]) { fprintf(stderr, "EACCES: %s\n", strerror(EACCES)); errno = ENOENT; perror(argv[0]); exit(0);}
通过将./a.out传入perror
函数,这样可以在管道中知道是哪个程序出错了。
错误恢复
在<errno.h>
的错误定义划分为两种:致命与非致命。致命错误没有恢复操作。而非致命错误相反,遇到此类错误时候可以更为妥善的处理。
资源相关的非致命错误包含EAGAIN, ENFILE, ENOBUFS, ENOLCK, ENOSPC, EWOULDBLOCK
,有些时候还有ENOMEM
。EBUSY
问题出在共享资源被占用的时候也可以视为非致命错误。
资源相关非致命错误的恢复策略一般是延迟重试。
适时的采用恢复策略可以增加应用的健壮性从而避免异常退出。
用户标识
用户ID
用户ID用来让系统区分不同的用户。
用户ID为0得用户为超级用户。操作系统的很多权限只向超级用户提供。
组ID
组ID是系统管理员在指定用户名提供的。这种机制允许组内成员共享资源。
组文件将组名映射为数字组ID,它通常是/etc/group.
举个栗子:
int main(int argc, char *argv[]) { printf("uid = %d, gid = %d\n", getuid(), getgid()); exit(0);}
附加组ID
大多数UNIX版本还允许一个用户属于另外一个用户组。
信号
信号是通知进程已经发生某种情况的一种技术。举个栗子,一个进程在执行除法运算操作,除数为0,则将名为SIGFPE的信号发给该进程。
栗子:
为了让程序能捕捉到信号,需要让其调用signal
函数来指定对应信号应当执行的动作(函数)。下栗是在捕获信号时候进行打印输出:
// 声明信号handlerstatic void sig_int(int);// 简单handler实体 - 打印void sig_int(int signo) { printf("interrupt\n%% ");}
时间值
UNIX系统有两类时间值:
- 日历时间
- 进程时间
日历时间:广义时间,用time_t
修饰。
进程时间:CPU时间,用来度量进程使用的CPU资源,用clock_t
修饰。进程时间又分为:
- 时钟时间 进程运行的时间总量。与总进程数有关。
- 用户CPU时间 CPU执行用户指令所用的时间
- 系统CPU时间 CPU执行内和程序所用的时间
用户CPU时间与系统CPU时间统称CPU时间。可以通过time
函数来获取时间值组成。
系统调用和库函数(理论)
从实现者角度看,系统调用和库函数之间有重大区别,但从用户角度,区别并不是很重要。
应用程序可以调用系统函数或者库函数,而很多库函数会调用系统调用。
系统调用通常提供最小接口,而库函数提供比较复杂的功能。
总结
UNIX概述
- Unix 基础
- unix基础
- Unix 基础
- Unix基础
- Unix基础
- Unix操作系统基础:Unix通信
- Unix操作系统基础:Unix:系统管理
- Unix操作系统基础:Unix 进程
- UNIX的基础
- Unix 操作系统基础手册
- Unix的基础哲学
- sco unix基础教材
- unix基础命令
- unix哲学基础
- Unix-Shell基础总汇
- Unix哲学基础
- Unix哲学基础
- 【Unix】Shell编程基础
- UEditor兼容新浪sae
- Command /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang
- JAVA代码效率优化
- Android AudioRecord 部分机型无法采集音频
- UITextField设置正文缩进
- Unix基础
- 2015
- 01 复杂系统结构
- PBOC/EMV之电子现金应用
- W3School 教程整理
- web framework 评估标准和评估方法 -- web框架哪家强?
- poj 3243 poj 2417 hdu 2815(解高次同余方程的应用)
- webpack- the next requireJS
- POI获取单元格值