信息安全系统设计基础第九周学习总结
系统级I/O
10.1 UNIX I/O
1.打开文件:一个应用程序要访问一个I/O设备,即要求内核打开相应文件。
2.描述符:内核返回一个小的非负整数,在后续对此文件的所有操作中标识这个文件。
-
标准输入(描述符0):STDIN_FILENO
-
标准输出(描述符1):STDOUT_FILENO
-
标准错误(描述符2):STDERR_FILENO
3.文件位置:从文件开头起始的字节偏移量k。应用程序能够通过执行seek操作,显式设置文件当前位置
10.2 打开和关闭文件
1.flags:
-
O_RDONLY:只读
-
O_WRONLY:只写
-
O_RDWR:可读可写
2.mode:mode与umask共同指定了新文件的访问权限位。
3.文件的访问权限位:mode & ~umask
umask:umask需要在打开文件前使用函数umask(umask);进行设置
10.3 读和写文件
1.返回:若成功则为实际传送的字节数量;-1表示错误;0表示EOF
fd:源文件的描述符
n:拷贝最多n个字节
buf:目标存储器位置
ssize_t write(int fd,const void *buf, size_t n);
2.返回:若成功则为实际写的字节数量;-1表示错误
buf:源存储器位置
n:拷贝最多n个字节
fd:目标文件的描述符
不足值出现情况:
读时遇到EOF
从终端读文本行
读和写网络套接字
10.4 用RIO包健壮地读写
RIO包会自动处理不足值。RIO提供了两类不同的函数:
无缓冲的输入输出函数。这些函数直接在存储器和文件之间传送数据,没有应用级缓冲,他们对将二进制数据读写到网络和从网络读写二进制数据尤其有用。
带缓冲的输入函数。这些函数允许你高效地从文件中读取文本行和二进制数据,这些文件的内容缓存在应用级缓冲区内,类似于像printf这样的标准I/O函数提供的缓冲区。是线程安全的,它在同一个描述符上可以被交错地调用。例如,可以从一个描述符中读一些文本行,然后读取一些二进制数据,接着再多读取一些文本行。
1.无缓冲输入输出:
include “csapp.h”
ssize_t rio_readn(int fd, void usrbuf, size_t n);
ssize_t rio_writen(int fd, void usrbuf, size_t n);
返回:
成功:传送的字节数
EOF:0
出错:-1
2.带缓冲的输入函数:
文本行:一个由换行符(0x0a)结尾的ASCII码字符序列
每打开一个描述符都会调用一次rio_readinitb函数,将描述符fd和地址rp处的一个类型为rio_t的读缓冲区联系起来
void rio_readinitb(rio_t *rp, int fd);
rio_readlineb函数从文件rp读一个文本行(包括换行符),到存储器位置usrbuf,用空字符结束文本行。至多读maxlen-1个字节,余下一个字符留给结尾空字符。超过maxlen-1部分会被截断。
ssize_t rio_readlineb(rio_t rp,void usrbuf, size_t maxlen);
rio_readnb从文件rp最多读n个字节到存储器位置usrbuf。
ssize_t rio_readnb(rio_t rp,void usrbuf, size_t n);
返回:
成功:读的字节数
EOF:0
出错:-1
对同一描述符,带缓冲区的函数调用可以任意交叉进行,但他们和无缓冲的调用不应交叉使用。
10.5 读取文件元数据
include <unistd.h>
include <sys/stat.h>
int stat(const *filename, struct stat *buf);
int fstat(int fd, struct *buf);
返回:成功为0;出错为-1
stat以文件名为输入,fstat以文件描述符为输入。
10.6 共享文件
- 没有共享文件,每个描述符对应一个不同文件。
- 多个描述符也可以通过不同的文件表表项来引用同一个文件。(每个描述符都有自己的文件位置,所以对不同描述符的读操作可以从文件的不同位置获取数据)
- 父子进程可以共享文件。子进程会有一个父进程描述符表项的副本,父子进程打开相同的文件表集合,共享相同的文件位置。在内核删除相应的文件表表项之前,父子进程都必须关闭相应的描述符表项。
- 文件表:当前文件位置,引用计数(当前指向该表项的描述符项数),以及一个指向V-node表对应表项的指针
- v-node表:包括st_mode和st_size成员
10.7 I/O重定向
- Unix外壳提供了I/O重定向操作符,允许用户将磁盘文件和标准输入输出联系起来
- 重定向使用dup2函数:int dup2(int oldfd,int newfd);
- dup2函数拷贝描述符表表项oldfd到描述符表表项newfd,覆盖描述表表项newfd以前的内容。
- 如果newfd已经打开,dup2会在拷贝oldfd之前关闭newfd