第1章 Unix系统编程概述
一 什么是系统编程
1.操作系统的职责
内存空间用来存放程序和数据,所有的程序必须在内存空间中才能运行。用来容纳操作系统的内存空间叫做系统空间,容纳应用程序的内存空间叫做用户空间。
二 理解系统编程
内核提供服务以便使系统程序可以直接访问系统资源
1.系统资源
- 处理器:内核安排一个程序何时开始执行,何时暂停、恢复、终止执行
- 输入输出(I/O):程序中所有输入输出都必须流经内核
- 进程管理
- 内存:内核的职责之一是内存管理,包括分配与回收
- 设备
- 计时器
- 进程间通信
- 网络
三 从用户角度理解Unix
1.登录
在登录过程中,当用户名和密码通过验证后,系统会启动一个叫做shell的进程,然后把用户交给这个进程,由这个进程处理用户请求。每个用户都有属于自己的shell进程。
2.目录操作
(1)目录树
(2)目录操作命令
- ls:列出目录内容
- cd:改变当前目录,只输入cd会立即回到用户主目录
- pwd:显示当前目录全路径
- mkdir,rmdir:新建,删除目录
3.文件操作
(1)文件操作命令
- cat,more,less,pg:查看文件内容
- cp:文件复制
- rm:文件删除
- mv:重命名或移动文件
四 从系统角度来看Unix
Unix系统编程中3个重要的方面:通信、协作、网络访问
四 动手实践
1.more的第一个实现版本
/* more01.c - version 0.1 of more01
* read and print 24 lines then pause for a few special commands
*/
#include<stdio.h>
#define PAGELEN 24
#define LINELEN 512
void do_more(FILE*);
int see_more();
int main(int argc,char* argv[])
{
FILE* fp;
if(argc==1)
do_more(stdin);
else
while(--argc)
if((fp=fopen(*++argv,"r"))!=NULL)
{
do_more(fp);
fclose(fp);
}
else
exit(1);
return 0;
}
void do_more(FILE* fp)
{
char line[LINELEN];
int num_of_lines=0;
int see_more(),replay;
while(fgets(line,LINELEN,fp))
{
if(num_of_lines==PAGELEN)
{
replay=see_more();
if(replay==0)
break;
num_of_lines-=replay;
}
if(fputs(line,stdout)==EOF)
exit(1);
num_of_lines++;
}
}
int see_more()
{
int c;
printf("\033[7m more?\033[m");
while((c=getchar())!=EOF)
{
if(c=='q')
return 0; /*不看*/
if(c==' ')
return PAGELEN; /*下一页*/
if(c=='\n')
return 1; /*下一行*/
}
return 0;
}
主函数中判断应从文件还是标准输入中获取数据,并打开相应的数据源,然后调用do_more函数,do_more函数将数据显示在显示器上,满一屏后,调用see_more函数接收用户的输入以决定下一步动作。运行结果如下:
问题:当屏幕上文字上滚时,more?也会随之上滚,这并不是所需要的。而且当按空格键或按q后,如果不按回车键,那程序什么也不会做。
管道是一种通信机制,通常用于进程间的通信(也可通过socket进行网络通信),它表现出来的形式将前面每一个进程的输出(stdout)直接作为下一个进程的输入(stdin)。管道命令使用|
作为界定符号。
当运行下列命令时,结果如下
ls /bin |more
而运行刚才的more01时,则有如下结果
ls /bin |./more01
可见其并未如more那样,这里管道符将more01
的标准输入重定向到ls
的标准输出,而more01的输入通过getchar()
函数读入。重定向后,more01将从同一个数据流中读用户的输入。
解决此问题的方法是,从标准输入中读入要分页的数据,直接从键盘读用户的输入。
在/dev/tty
处有键盘和显示器的设备描述文件,向这个文件写,相当于显示在用户的屏幕上,读则相当于从键盘获取用户的输入。more命令有两个输入:程序的标准输入是ls的输出,将其分页显示到屏幕上,当more需要用户输入时,可以从/dev/tty
得到数据。
改进more01.c为more02.c
/* more02.c - version 0.2 of more01
* read and print 24 lines then pause for a few special commands
* feature of version 0.2:reads from /dev/tty for commands
*/
#include<stdio.h>
#define PAGELEN 24
#define LINELEN 512
void do_more(FILE*);
int see_more(FILE*);
int main(int argc,char* argv[])
{
FILE* fp;
if(argc==1)
do_more(stdin);
else
while(--argc)
if((fp=fopen(*++argv,"r"))!=NULL)
{
do_more(fp);
fclose(fp);
}
else
exit(1);
return 0;
}
void do_more(FILE* fp)
{
char line[LINELEN];
int num_of_lines=0;
int see_more(FILE*),replay;
FILE* fp_tty;
fp_tty=fopen("/dev/tty","r");
if(fp_tty==NULL)
exit(1);
while(fgets(line,LINELEN,fp))
{
if(num_of_lines==PAGELEN)
{
replay=see_more(fp_tty);
if(replay==0)
break;
num_of_lines-=replay;
}
if(fputs(line,stdout)==EOF)
exit(1);
num_of_lines++;
}
}
int see_more(FILE* cmd)
{
int c;
printf("\033[7m more?\033[m");
while((c=getc(cmd))!=EOF) /*从文件流中读取下一个字符*/
{
if(c=='q')
return 0; /*不看*/
if(c==' ')
return PAGELEN; /*下一页*/
if(c=='\n')
return 1; /*下一行*/
}
return 0;
}
程序编译运行结果如下:
more02还需进一步完善,以使得不需要额外的回车,并且输入的字符也不会回显。
用户操作的终端有很多参数,可以调整参数使得用户输入的字符被立即送到程序,而不用等待回车,还可以使输入的字符不回显。