【Unix/Linux编程实践】从零做起:编写who命令

《Unix/Linux编程实践教程》着实有意思。

通常我们要做一件事情,会想着先储备足够的知识再来动手。但繁杂的知识往往成为一个问题,因此快速的学习能力显得尤为重要。说这本书有意思,是因为作者不是一上来就把知识点罗列出来,而是教我们如何一步步去获得我们需要的信息or知识。

下面我们看看怎样从零开始,编写一个简单的who命令!

1.who命令能够做什么?

#首先,实际使用一下~
$ who

#查看联机帮助
$ man who

2.who命令是如何工作的?

#阅读联机帮助
$ man who

从联机帮助中我们可以知道,已登陆用户的信息是放在文件/var/adm/utmp中的,who通过读取该文件来获取信息。

另外,帮助里说,文件的格式是 utmp(4),那么我们循着这一步看一下:

$ man 4 utmp

(此外,我们可以通过 man -k utmp来搜索联机帮助,-k选项可以根据关键字来搜索联机帮助)

从联机文件里我们可以知道,utmp文件里保存的是结构数组,数组元素是utmp类型的结构,我们可以在utmp.h中找到utmp类型的定义!而utmp.h存放在/usr/include目录中。

所以下一步我们可以查看下utmp.h:

$ more /usr/include/utmp.h

通过联机文件,我们从一开始对who一无所知,到现在的初步了解,不得不说man真的很好用!

现在,我们可以猜测下who的工作原理:打开/var/adm/utmp文件,从文件中读取数据结构数组,然后显示出来!

3.如何编写who?

我们需要做的两件事:

1.从文件中读取数据结构

2.将结构中的信息以合适的形式显示出来

问题1:如何从文件(file)读取(read)数据结构?

#搜索与fileread有关的主题
$ man -k file | grep read

我们可以找到一个可能的目标: read(2)

$ man 2 read

通过这个我们可以知道,该系统调用可以将文件中一定数目的字节读入一个缓冲区——为读取一个数据结构,我们可以用sizeof(struct utmp)来指定每次读入的字节数。另外,read打开的是文件描述符,那么如何获得文件描述符呢?

我们可以从联机帮助中的RELATED INFORMATION中看到一个open(2),也许这个是我们要找的,于是可以查看open的联机帮助,从中我们又可以找到close!

所以答案是:使用open,read,close。

接下来的工作就是读懂这3个系统调用的用法,然后付诸实践!

4.实践

/* who1.c - a first version of the who program * open, read UTMP file, and show results */
#include <stdio.h>
#include <utmp.h>
#include <fcntl.h>
#include <unistd.h>

#define SHOWHOST /* include remote machine on output */

int main()
{
    struct utmp current_record; /* read info into here */
    int     utmpfd;     /* read from this descriptor */
    int     reclen = sizeof(current_record);

    if ( (utmpfd = open(UTMP_FILE, O_RDONLY)) == -1 ){
        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;           /* went ok */
}
/* * show info() * displays contents of the utmp struct in human readable form * *note* these sizes should not be hardwired */
show_info( struct utmp *utbufp )
{
    printf("%-8.8s", utbufp->ut_name);  /* the logname */
    printf(" ");                /* a space */
    printf("%-8.8s", utbufp->ut_line);  /* the tty */
    printf(" ");                /* a space */
    printf("%10ld", utbufp->ut_time);   /* login time */
    printf(" ");                /* a space */
#ifdef SHOWHOST
    printf("(%s)", utbufp->ut_host);    /* the host */
#endif
    printf("\n");               /* newline */
}

编译运行,我们发现有一些问题:
存在空白的记录;
登陆时间格式显示有问题;

针对这两点的解决方法我就不在这里细说啦~

整体感受下来,思路很清晰,作者从初学者的角度,一点一点把我们想要的知识,信息纠出来,虽然很简单,但是跟随作者的节奏实践下来,真的觉得很爽!

在举了who的例子之后,作者又给了一个实现cp的例子,十分简单。这样子看来,好像UNIX编程挺简单的?

我们要明白,虽然功能是实现了,但是如果文件太大,那么在读,写的时候,岂不是要花费很多时间?

于是我们要再多问一个问题:如何使你的程序运行得更加有效率?

——答案是,使用缓冲。

为什么系统调用需要很多时间?

——因为系统调用在内核中,执行的时候需要从用户态切换到内核态,这个切换过程需要消耗大量时间。

在who1.c中,我们每次从utmp中读取一条记录,就像我们要煎3个蛋一样,去超市买一个,煎好,再买一个,再煎,再去买……

明智的做法应该是一次性买3个!

对应的,who程序中,我们可以一次性读取多个,比如16个utmp结构,然后显示,这样子效率就有所提高了。

缓冲技术在操作系统中应用很广泛,比如标准I/0等等~

你可能感兴趣的:(【Unix/Linux编程实践】从零做起:编写who命令)