Linux编程实战读书笔记 第2章

Linux编程实战读书笔记 第2章 

前言:该章展示了联机帮助的作用和使用方法,linux中文件操作相关的接口函数、参数知识,内核模式和用户模式,系统调用的代价等;最后自己编写实现一个简单的who命令。

2.2 命令who

上图最大的长方形为计算机内存,分为用户空间和系统空间;三个较小的长方体为应用程序,运行在用户空间,而底部的长方形为内核程序,应用程序通过内核与外界进行通信;最底部两个圆柱体为两个硬盘,一些小的管道则为通信管道;其他为一些外部设备,如打印机、屏幕、键盘等。

学习who命令则要了解三个问题:

1. who命令能干啥

2. who命令怎么工作的

3. 如何编写who

命令也是程序

2.3 问题1:who能干啥

在命令行打who,便会得到现在系统中登陆的用户。

还可以通过man who阅读who的手册,在手册中会有详细的描述,其的作者、使用、位置等。

2.4 问题2:who是如何工作的?

书中使用的系统是SunOS平台,本人使用的ubuntu平台,who手册中描述的没有那么详细,如下图:

再图中提到两个文件,/var/run/utmp,/var/log/wtmp,跟书中的位置不同,文件名称相同,已登陆的用户信息会存放在/var/run/utmp,通过联机帮助来了解该文件的结构信息。

命令行输入man -k utmp则可以查找“utmp”相关的信息,如图:

书中会查看utmp(4),但是ubuntu没有这个,则选择utmp(5),查看其帮助内容,在命令行输入man 5 utmp,如图:

在内容里面是utmp.h文件内容,utmp结构体也在其中,可以很好了解该数据结构包含的信息,因为已经过了很多迭代,与书中的改变已经很大,但结构体中的成员还是差不多的。

结构体中每个成员都会有相应的注释,可以解读到用户u名、用户登陆设备等信息。

根据上述总结,who的工作流程如图:

接下来则可以通过读取utmp文件获取登陆信息数据,最后编写一个简单的who命令。

2.5 编写who

知道要对utmp文件进行读取,这时候先去了解文件操作的read、open、close函数的使用。想了解file和read相关的帮助,可以在命令行输入man -k file | grep read,就会输出文件read相关的接口。

如图中的read(2)就是相关函数,在输入man 2 read,则可阅读相关帮助。

在帮助中就有函数描述,怎么调用,返回值有什么意义。open,close,read三个函数就是实现的基本,阅读他们的帮助。

open函数注意:内核允许多进程访问文件,多次打开是允许的,多次打开对应的文件描述符也不相同。read函数读取数据就会返回读取的数据大小

编写时需多查看文档,其中liunx中的utmp结构体中时间结构体为timeval结构体,使用man -k time | grep timeval可查看相关帮助,其结构为

linux中对于时间戳有相应的转换函数ctime函数,可以将timeval结构体中的tv_sec成员变为字符串。

最后代码为:

/*who1.c - who命令初版                                   
 *          open, read UTMP file,and show results        
 *         版本2:只显示用户类型、同时显示正确时间格式
 */
#include <stdio.h>
#include <stdlib.h>
#include <utmp.h>
#include <fcntl.h>
#include <unistd.h>
#include <time.h>

#define SHOWHOST     //include remote machine on output

//登陆信息展示函数
void show_info(struct utmp *utbufp);
//登陆时间显示函数
void show_time(time_t tv_sec);

int main(){
        struct utmp current_record; //读出的信息保存在该结构体
        int utmpfd;                 //文件操作符
        int reclen = sizeof(current_record);//每次读出utmp结构体大小数据

        if((utmpfd  = open(UTMP_FILE,O_RDONLY))==-1){//打开utmp文件
                perror(UTMP_FILE);  //UTMP_FILE is in utmp.h
                exit(1);
        }

        while(read(utmpfd,&current_record,reclen)==reclen)//读出所有数据
                show_info(&current_record);
        close(utmpfd);
        return 0;
}

void show_info(struct utmp* utbufp){
        if(utbufp->ut_type != USER_PROCESS) return;//不是用户类型不显示 
        printf("%-8.8s",utbufp->ut_user);//用户名
        printf(" ");
        printf("%-8.8s",utbufp->ut_line);//用户登陆设备名
        printf(" ");
        show_time(utbufp->ut_tv.tv_sec);//展示登陆时间
#ifdef SHOWHOST
        printf("(%s)",utbufp->ut_host);//登陆主机地址
#endif
        printf("\n");
}

void show_time(time_t tv_sec){
        char *cp;
        cp = ctime(&tv_sec);//将时间戳变为字符串
        //大概为Mon Feb 4 00:46:40 EST 1991这样的格式
        printf("%15.24s",cp);//简单打印时间
        printf(" ");
}

2.6 编写cp

cp命令是再熟悉不过了,cp即复制,该命令会使用文件操作的create函数进行创建新文件。

create函数创建文件时会传入两个参数,一个是文件名如果文件名不存在则创建新的,如果存在则将存在的文件清空,文件长度为0;第二个为文件的操作许可模式,设置可读可写的等级,创建成功会返回一个文件操作符。当然还需要write函数进行写入,编写流程如下:

这时候编写比较简单,就是打开读然后写到新的文件中去,再ubuntu中cp如果第二个参数是路径则可以将文件复制过去。

2.7 提高文件I/O效率的方法:使用缓冲

系统调用需要时间,使用缓冲就是利用空间换取时间,如图所示为系统调用控制流图。

当读取磁盘数据时需要调用read代码。read代码在内核中,所以当read调用时,执行权会从用户代码到内核代码中。

用户态到内核态需要切换一些特殊的堆栈和内存环境,所以系统调用的开销大。

对于之前所编写who2.c中是十分低效的,每次只拿取一个用户的信息,然后打印完成后在去取下一个的,这里可以与cp类似使用缓存事先读取多个用户信息。

根据书中的代码编写,本人添加了头文件这样编写时候方便,代码简单就不贴出来。

2.8 内核缓存技术

磁盘的I/O操作消耗的时间更多,为了提高效率,内核也是用缓冲技术来提高对磁盘的访问速度,如图所示:

内核将磁盘上的数据块复制到内核缓冲区中,当一个用户空间中的进程要从磁盘读取数据是,内核一般不直接读磁盘,而是将内核缓冲区的数据复制到进程的缓冲区去。

可能进程访问的数据块不在内核缓冲区,内核会将相应的数据块加入到请求数据队列表中,先将进程挂起;将数据块读到缓冲区后,再把数据复制到进程的缓冲区,最后唤醒被挂起的进程。读和写都会由缓存区这么一个步骤,写需要到一定数量才会一次写入;断电可能会导致缓存器清空,内核来不及将数据写入。

之后章节中会展示文件读写中的lseek用于定位文件指针,还有处理系统错误,在之前的编写中对于错误的处理已经有了。

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值