总所周知,UNIX环境高级编程是一本很经典的书,之前我粗略的看了一遍,感觉理解得不够深入。

听说写博客可以提高自己的水平,因此趁着这个机会我想把它重新看一遍,并把每一章的笔记写在博客里面。

我学习的时候使用的平台是Windows+VMware+debian,使用secureCRT来连接(可以实现多个终端连接)。

因为第一章是本书大概的描述,所以第一章的我打算写得详细一点,而且书本的原话占的比例会比较多,重点的东西会用粗体显示出来。

1.1  引言

所有操作系统都为他们所运行的程序提供服务。典型的服务包括:执行新程序、打开文件、读文件、分配存储区以及获取当前时间等,

本书集中阐述不同版本的UNIX操作系统所提供的服务。

本章会简要的介绍UNIX提供的各种服务,在以后的各章中将对这些概念做更详细的说明。

1.2  UNIX体系结构

从严格意义上说,可将操作系统定义为一种软件,它控制计算机硬件资源,提供程序运行环境。我们通常将这种软件称为内核

下图显示了UNIX系统的体系结构,其它部分下面会逐个讲到。

1.3  登录

1 登录名

用户在登录UNIX系统时,先键入登录名,然后键入口令。系统在其口令文件(通常是/etc/passwd文件)中查看用户名。

2 shell

用户登录后,系统通常先显示一些系统信息,然后用户就可以向shell程序键入命令。

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

1.4  文件和目录

1 文件系统

UNIX文件系统是目录和文件的一种层次结构,所有东西的起点都是根的目录,这个目录名称是一个字符“/”

目录是一个包含目录项的文件,可以认为每个目录项都包含一个文件名,同时还包含该文件属性的信息(ls -l可以查看)。第四章会详细说明文件的各种属性。

2 文件名

目录中的各个名字成为文件名,创建目录时会自动创建两个文件名:.(当前目录)和..(父目录)   (可见为什么 cd .. 会回到父目录)

3 路径名

已斜线开头的路径名称成为绝对路径名(可以理解为以根目录开头的相对路径名),否则为相对路径名。

不难列出一个目录中所有文件的名字,下面是ls(1)命令的简要实现

其中apue.h可以通过网上下载,http://blog.csdn.net/istruth/article/details/44201827有下载地址和使用的方法,后面章节会详细的给出下列函数的用法。

#include "apue.h"
#include <dirent.h> int main(int argc,char *argv[])
{
DIR *dp;
struct dirent *dirp;
if(argc!=)
err_quit("usage:ls directory_name");
if((dp=opendir(argv[]))==NULL)
err_sys("can't open %s",argv[]);
while((dirp=readdir(dp))!=NULL)
printf("%s\n",dirp->d_name);
closedir(dp);
exit();
}

可以使用gcc编译该文件  执行命令cc myls.c进行编译   会生成a.out文件  执行./a.out命令来运行  (./代表当前目录,如果不指定,系统会在环境变量中设置的路径中找可执行文件)

4  工作目录

每个进程都有一个工作目录,有时称其为当前工作目录,进程可以用chdir函数更改其工作目录

5 起始目录

登录时,工作目录设置为起始目录,该起始目录从口令文件中相应用户的登录项中取得。

1.5  输入与输出

1 文件描述符

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

它都返回一个文件描述符,可以通过这个文件描述符进行读写文件

2  标准输入、标准输出和标准错误

每当运行一个新程序时,所有的shell都为其打开3个文件描述符,即标准输入(0)、标准输出(1)和标准错误(2),如果不做特殊处理,

则这3个描述符都链接到终端。

3  不带缓冲的I/O

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

下面程序展示了如何复制UNIX下的普通文件

#include "apue.h"

#define BUFFSIZE 4096

int main(void)
{
int n;
char buf[BUFFSIZE];
while((n=read(STDIN_FILENO,buf,BUFFSIZE))>)
if(write(STDOUT_FILENO,buf,n)!=n)
err_sys("write error");
if(n<)
err_sys("read error");
exit();
}

大多数shell都提供一种方法,使其中任何一个或所有这3个描述符都能重定向到某个文件。例如ls > file.list 可以将ls的输出(标准输出 文件描述符为1)重定向到名为file.list的文件。

如下执行上面的程序: ./a.out > data 可以把程序的标准输出重定向到文件data   ./a.out < infile > outfile 把程序的标准输入重定向到infile  把标准输出重定向到outfile,实现了文件的复制。

4  标准I/O

标准I/O 为那些不带缓冲的I/O函数提供了一个带缓冲的接口,下面演示使用标准I/O复制UNIX文件

#include "apue.h"

int main(void)
{
int c;
while((c=getc(stdin))!=EOF)
if(putc(c,stdout)==EOF)
err_sys("output error");
if(ferror(stdin))
err_sys("input error");
exit();
}

1.6 程序与进程

1 程序

程序是一个存储在磁盘上某个目录中的可执行文件

2 进程和进程ID

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

下面程序用于打印进程ID

#include "apue.h"

int main(void)
{
printf("hello world from process ID %ld\n",(long)getpid());
exit();
}

3 进程控制

有3个用于进程控制的主要函数:fork、exec和waitpid。

UNIX系统的进程控制功能可以用一个简单得程序说明,下面程序从标准输入读取命令,然后执行命令,类似于shell程序的基本实施部分。

#include "apue.h"
#include <sys/wait.h> int main(void)
{
char buf[MAXLINE];
pid_t pid;
int status;
printf("%% ");
while(fgets(buf,MAXLINE,stdin)!=NULL)
{
if(buf[strlen(buf)-]=='\n')
buf[strlen(buf)-]=;
if((pid=fork())<)
err_sys("fork error");
else if(pid==)
{
execlp(buf,buf,(char *));
err_ret("couldn't execute:%s",buf);
exit();
}
if((pid=waitpid(pid,&status,))<)
err_sys("waitpid error");
printf("%% ");
}
exit();
}

4  线程和线程ID

与进程相同,线程也用ID标识。但是,线程ID只在它所属的进程内起作用。

1.7  出错处理

当UNIX系统函数出错时,通常会返回一个负值,而且整形变量errno通常被设置为具有特定信息的值。

文件<error.h>中定义了error以及可以赋予它的各种常量。

C标准定义了两个函数,用于打印出错信息

#include <string.h>
char *strerror(int errnum);

strerror函数将errnm(通常就是error值)映射为一个出错消息字符串,并且返回此字符串的指针。

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

perror函数基于errno的当前值,在标准错误上产生一条出错信息,然后返回。

下面程序显示这两个出错函数的使用方法

#include "apue.h"
#include <errno.h> int main(int argc,char *argv[])
{
fprintf(stderr,"EACCES:%s\n",strerror(EACCES));
errno=ENOENT;
perror(argv[]);
exit();
}

1.8  用户标识

1 用户ID

用户ID是一个数值,用来确定一个用户。用户ID为0为根用户或超级用户,超级用户对系统有自由的支配权。

2 组ID

组ID是由系统管理员在指定用户登录名时分配的,可以把多个用户分成一组。

下面程序用于打印用户ID和组ID

#include "apue.h"

int main(void)
{
printf("uid=%d,gid=%d\n",getuid(),getgid());
exit();
}

3 附属组ID

除了在口令文件中对一个登录名指定一个组ID之外,大多数UNIX系统版本还允许一个用户属于另外一些组。

1.9 信号

信号用于通知进程发生了某种情况。例如,若某一进程执行除法操作,其除数为0,则将名为SIGFPE(浮点异常)的信号发送给进程。

进程有以下3种处理信号的方式:

1 忽略信号

2 按系统默认方式处理

3 提供一个函数,信号发生时调用该函数,这被称为捕捉该信号。

终端键盘上有两种产生信号的方法,分别称为中断键(通常是Delete或Ctrl+C)和退出键(通常是Ctrl+\)

修改之前的shell实例,使程序可以捕获SIGINT信号,我们会在第10章详细的介绍信号。

#include "apue.h"
#include <sys/wait.h> static void sig_int(int); int main(void)
{
char buf[MAXLINE];
pid_t pid;
int status;
if(signal(SIGINT,sig_int)==SIG_ERR);
err_sys("signal error");
printf("%% ");
while(fgets(buf,MAXLINE,stdin)!=NULL)
{
if(buf[strlen(buf)-]=='\n')
buf[strlen(buf)-]=;
if((pid=fork())<)
err_sys("fork error");
else if(pid==)
{
execlp(buf,buf,(char *));
err_ret("couldn't execute:%s",buf);
exit();
}
if((pid=waitpid(pid,&status,))<)
err_sys("waitpid error");
printf("%% ");
}
exit();
}
void sig_int(int signo)
{
printf("interrupt\n%%");
}

1.10  时间值

历史上,UNIX系统使用过两种不同的时间值

1 日历时间。该值是从1970年1月1日00:00:00这个特定时间以来所经过的秒数的累计值。

2 进程时间。也被称为CPU时间

当度量一个进程的执行时间时,UNIX系统为一个进程维护了3个进程时间值

时钟时间  即进程运行的时间总量,其值与系统中同时运行的进程数有关

用户CPU时间  执行用户指令所用的时间量

 系统CPU时间  执行系统调用的时间

1.11 系统调用和库函数

系统调用提供的函数如open, close, read, write, ioctl等,系统调用发生在内核空间

标准C库函数提供的文件操作函数如fopen, fread, fwrite, fclose, fflush, fseek等属于库函数,底层也是通过系统调用来实现的

最新文章

  1. VC++6.0文件关联问题的解决方法
  2. 汉诺塔算法详解之C++
  3. html添加网络音乐
  4. 《Web 开发基础》专题系列
  5. Android的Observable和iOS的NotificationCenter
  6. c#中如何将一个string数组转换为int数组
  7. django模型中的抽象类(abstract)
  8. puppet aix package 之rsync安装
  9. Oracle_Q&amp;A_03
  10. Google瓦片地图算法解析
  11. web前端除了关注代码功能实现,还应具备web性能优化以及SEO优化的常识
  12. Windowsclient SSH 远程连接Windowsserver(PowerShell Server)
  13. angularjs指令实现轮播图----swiper
  14. Android.HowToDesignPluginArchitectureInAndroidApp
  15. Mac 安装zsh
  16. #HTTP协议学习# (八)状态码详解
  17. 【BZOJ1835】基站选址(线段树)
  18. Centos中查询目录中内容命名ls
  19. BottomNavigationView结合ViewPager
  20. css中的定位问题

热门文章

  1. pip3 快速安装
  2. STM in Haskell
  3. tcpreplay 缓存算法研究
  4. 关于java1.7集合源码阅读
  5. AC日记——Little Elephant and Problem codeforces 221c
  6. 请教一下16aspx上的源代码要如何在自己的服务器上运行
  7. HDU 6038.Function-数学+思维 (2017 Multi-University Training Contest - Team 1 1006)
  8. (转)代码中实现button
  9. [TopCoder8600]MagicFingerprint
  10. linux-配置字符串-grep