who的工作原理:
通过读utmp文件获得需要的信息,而每个登录的用户在文件中都有对应的记录。
文件中的结构数组存放登录用户的信息,所以直接的想法就是把记录一个一个地读出并显示出来。
文件操作函数:open read write seek close perror
1.open():这个系统调用在进程和文件之间建立一条连接,这个连接被称为文件描述符。
用法:int fd = open (char * name, int how); //how的取值:O_RDONLY, O_WRONLY, O_RDWR
2.read(): 这个系统调用请求内核从fd所指定的文件读取qty字节的数据,放到buf所指定的内存空间中。
用法:ssize_t numread = read (int fd, void * buf, size_t qty);
3.close():这个系统调用会关闭进程和文件fd之间的连接。
用法:int result = close (int fd);
4.create():这个系统调用告诉内核创建一个名为filename的文件,如果这个文件不存在,就创建它,如果已经存在,就把它的内容清空,把文件的长度设为0。
用法:int fd = create(char *filename, mode_t mode);
5.write():这个系统调用高速内核讲内存中指定的数据写入文件。
用法:ssize_t result = write( int fd, void *buf, size_t amt);
6.lseek():使指针指向文件中的指定位置。
用法:off_t oldpos = lseek(int fd, off_t dist, int base);
其它一些涉及到的函数:
printf() :标准库函数
用法:printf("格式控制字符串",输出表列)
格式字符串的一般形式:[标志][输出最小宽度][.精度][长度]类型
标志:-,+,#和空格四种
输出最小宽度:用十进制整数表示输出的最少位数。若实际位数多于定义的宽度,则按实际位数输出;若少于,则补空格或0。
.精度:如果输出数字,则表示小数的位数;如果输出字符,则表示字符的个数。
长度:h,l两种。短整型和长整型。
fprintf(): 标准库函数,类似printf
函数定义:int fprintf (FILE * stream, const char *format, [argument]); 返回输出的字符数
作用:根据指定的格式(format)将信息(argument)发送到文件流(stream)
perror(): 错误输出函数
函数定义:void
perror
(
const
char
* str );
输出内容(屏幕上):str:错误信息;若没有错误,则输出str:error 0
exit():库函数,调用_exit()系统调用,对其做了一些封装,执行之前检查文件打开情况,并将缓冲区中数据写入文件。
作用:关闭所有文件,终止正在运行的进程
exit(0):表示正常退出
exit(非零):表示异常退出,并将参数返回给操作系统。
缓冲:用户级的缓冲和内核级的缓冲
用户级的缓冲:从内核缓冲区读取数据到用户空间
内核级的缓冲:从磁盘读取数据缓存到内核缓冲区
内核模式、用户模式和系统调用的代价
系统调用会消耗很多时间。
在cp命令中,用户进程位于用户空间,内核位于系统空间,磁盘只能被内核访问。程序cp要读取磁盘上的数据只能通过系统调用read,而read的代码在内核中,所以当read调用时,执行权会从用户代码转移到内核代码,执行内核代码是需要时间的。
系统调用的开销大不仅仅是因为要传输数据,当运行内核代码时,CPU工作在管理员模式(又称超级用户模式),这对应于一些特殊的堆栈和内存环境,必须在系统调用发生时建立好,系统调用结束后,CPU又得切换到用户模式,并且恢复之前的堆栈信息。即上下文切换需要消耗时间。
代码地址:https://github.com/zhanghuanlucy/Unix-Linux-Programming