Unix/Linux 编程實踐教程
## 什麼是系統編程
系统资源
- 处理器
程序由指令构成,处理器是执行指令的硬件设备,一个系统中可能有多个处理器,内核可以安排一个程序何时开始开始执行,暂时停止,恢复执行,终止执行
- 输入输出
程序中所有的输入输出都必须流经内核,集中处理,保证了系统的正确性,安全性,有效性
- 进程管理
每个程序执行都必须有自己的资源,内核可以新建进程,中止进程,进程调度
- 内存
程序必须被装载到内存中才能运行,内核可以对进程进行管理,在程序需要的时候给程序分配内存,当程序不需要时,回收内存,还可以保证内存不被其他进程非法访问.
- 设备
各种设备的操作方式不相同,通过内核,可以屏蔽這種差异,使我们对设备的操作简单统一
- 计时器
程序的工作和时间有关,内核可以通过系统调用向应用程序提供计时器服务
- 进程间通信
内核可以让进程之间进行通信
- 网络
内核可以让不同主机上的不同进程进行通信
bc:Unix计算器,可以接受逆波兰表达式
通过他的与处理器dc,转换为逆波兰表达式,通过pip给dc
和web服务类似,web服务器作为預处理器,浏览器作为前端显示
more:
more filename,分页显示file内容
command | more:分页显示command命令
more < filename:分页+重定向
自己写一个more
//more command
#include<stdio.h>
#include<stdlib.h>
#define PAGELEN 24
#define LINELEN 512
void do_more(FILE* );
int see_more(FILE*,int );
int sum_size = 0;
int main(int ac,char *av[])
{
FILE* fp;
if(ac == 1)
do_more(stdin);
else
while(--ac)
{
if((fp = fopen(*++av,"r")) != NULL)
{
fseek(fp,0L,SEEK_END); /*利用fseek函数将指针定位在文件结尾的位置*/
sum_size=ftell(fp); /*利用ftell函数返回指针相对于文件开头的位置,以字节计算*/
printf("\n the type of file is : %d\n",sum_size); /*进行输出文件总大小*/
fseek(fp,0L,SEEK_SET); /*将fp设置文件开始的位置*/
do_more(fp);
fclose(fp);
}
else
exit(1);
}
return 0;
}
void do_more(FILE* fp)
{
/*
read PAGELEN lines, then call see_more() for further instructions
*/
char line[LINELEN];
int num_of_lines = 0;
int see_more(FILE*,int),reply;
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)
{
int cur_size=ftell(fp); /*利用ftell函数返回指针相对于文件开头的位置,以字节计算*/
int per= (int)100* cur_size/sum_size; //计算当前占用比例。
reply =see_more(fp_tty,per);
if(reply == 0 )
break;
num_of_lines -= reply;
}
if(fputs(line,stdout) == EOF)
exit(1);
num_of_lines++;
}
}
int see_more(FILE* cmd,int per)
{
/*
print message, wait for response, return # of lines to advance
q means no, space means yes CRmeans one line
*/
int c;
system("stty -icanon");//关闭缓冲区,输入字符无需回车直接接受
printf("\033[7m more?##%d##\033[m",per); //实现反白
while((c=getc(cmd))!=EOF)
{
if(c == 'q')
return 0;
if(c == ' ')
return PAGELEN;
if(c == '\n')
return 1;
}
}
who
查看有哪些用户在使用这台电脑
自己写一个who:
需要的步骤:
#直接运行,了解大致的功能
who
#查看文档
man who
#可以看到,大致放在utmp这个文件中
#根据关键词查看帮助
man -k utmp
#结果可以看到在帮助手册的第3节
man 3 utmp
#结果中,可以知道这是一个数据结构,定义在某个.h文件中
#从文件中读取数据结构
man -k file | egrep read
#于是我们找到了read(),进去看如何调用
#顺便,他还介绍了close()和open()
#思路:
#从utmp中读取我们需要的信息,循环输出
#关于怎么输出时间
man -k time | egrep transform
#结果你应该可以看到ctime
man 3 ctime
## 开始写吧:
who:
#include<stdlib.h>
#include<stdio.h>
#include<utmp.h>
#include<fcntl.h>
#include<unistd.h>
#include<time.h>
#define SHOWHOST
#define USER_PROCESS 7
void showtime(long);
void show_info(struct utmp * utbufp){
if(utbufp->ut_type != USER_PROCESS)
return;
printf("%-8.8s",utbufp->ut_name);
printf(" ");
printf("%-8.8s",utbufp->ut_line);
printf(" ");
showtime(utbufp->ut_time);
#ifdef SHOWHOST
if(utbufp->ut_host[0] != '\0')
printf("(%s)",utbufp->ut_host);
#endif
printf("\n");
}
void showtime(long timeval){
char *cp;
cp = ctime(&timeval);
printf("%12.12s",cp+4);
}
int main(){
struct utmp current_record;
int utmpfd;
int reclen = sizeof(current_record);
if((utmpfd = open(UTMP_FILE,O_RDONLY)) == -1){
perror(UTMP_FILE);
exit(1);}
while (read(utmpfd,¤t_record,reclen) == reclen)
show_info(¤t_record);
close(utmpfd);
return 0;
}
#使用缓冲区的who
#include<stdlib.h>
#include<stdio.h>
#include<utmp.h>
#include<fcntl.h>
#include<unistd.h>
#include<time.h>
#define SHOWHOST
#define USER_PROCESS 7
#define NRECS 16
#define NULLUT ((struct utmp*)NULL)
#define UTSIZE (sizeof(struct utmp))
static char utmpbuf[NRECS * UTSIZE];
static NULLUT ()
void showtime(long);
void show_info(struct utmp * utbufp){
if(utbufp->ut_type != USER_PROCESS)
return;
printf("%-8.8s",utbufp->ut_name);
printf(" ");
printf("%-8.8s",utbufp->ut_line);
printf(" ");
showtime(utbufp->ut_time);
#ifdef SHOWHOST
if(utbufp->ut_host[0] != '\0')
printf("(%s)",utbufp->ut_host);
#endif
printf("\n");
}
void showtime(long timeval){
char *cp;
cp = ctime(&timeval);
printf("%12.12s",cp+4);
}
int main(){
struct utmp current_record;
int utmpfd;
int reclen = sizeof(current_record);
if((utmpfd = open(UTMP_FILE,O_RDONLY)) == -1){
perror(UTMP_FILE);
exit(1);}
while (read(utmpfd,¤t_record,reclen) == reclen)
show_info(¤t_record);
close(utmpfd);
return 0;
}
cp
cp命令把源文件复制到目标文件,如果目标文件不存在,就创建这个命令,如果已经存在就覆盖
创建和重写文件:
系统调用函数creat:
int fd = creat(char *filename,mode_t mode)
mode:如果内核成功创建了file,则把mode设置为许可位
系统调用函数write:
ssize_t result = write(int fd,void *buf,size_t amt)
提高文件i/o效率的方法:使用缓冲
系统调用是需要时间的:
当这个程序去调用read时,read的代码在内核中。
系统调用开销大的原因:
内核和程序之间不只是会传输数据,还会在root模和用户模式之间来回切换
Comments