信息安全系统设计基础第八周总结

系统级I/O

10.1 Unix I/O

(1)一个Unix文件就是一个m个字节的序列:B0,B1,B2,B3...Bk...Bm-1。

(2)所有的I/O设备,如网络、磁盘盒终端,都被模型化为文件,而所有的输入和输出都被当做对相应的文件的读和写来执行。这是一种应用接口,成为Unix I/O。

这使得所有的输入和输出都能以一种统一且一致的方式来执行:

①打开文件

②改变当前的文件位置。

③读写文件。

④关闭文件。

(3)

①输入是从I/O设备拷贝数据到主存,输出是从主存拷贝数据到I/O设备。

②一个文件就是一个字节序列。

③所有的I/O设备,如网络、磁盘、和终端,都被模型化为文件,而所有的输入和输出都被当做想对应的文件的读写来执行。

10.2 打开和关闭文件

(1)进程是通过调用open函数来打开一个已存在的文件或者创建一个新文件的

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <unistd.h>

(2)创建一个新文件,文件的拥有者有读写权限,而所有其他的用户都有读权限

umask(DEF_UMASK);

fg=Open("foo.txt",O_CREAT|O_TRUNC|O_WEONLY,DEF_MODE);

(3)通过调用close函数关闭一个打开的文件

int close(int fd);//返回值成功为0,出错为-1

10.3 读和写文件

(1)应用程序是通过分别调用read和write函数来执行输入和输出的

(2)read函数从描述符为fd的当前文件位置拷贝最多n个字节到存储器位置buf,返回值-1表示一个错误。而返回值0表示EOF。否则,返回值表示的是实际传送的字节数量

(3)write函数从存储器位置buf拷贝至多n个字节到描述符fd的当前文件位置

(4)通过调用lseek函数,应用程序能够显示地修改当前文件的位置

(5)在某些情况下,read和write传送的字节比应用程序要求的要少,这些不足值不表示有错误

读时遇到EOF。假设我们猪呢比读一个文件,该文件从当前文件位置开始只含有20多个字节,而我们以50个字节的片进行读取。这样一来,下一个read返回的不足值为20,此后的read将通过返回不足值0来发出EOF信号。

从终端读文本行。如果打开文件是与终端相关联的(如键盘和显示器),那么每个read函数将以此传送一个文本行,返回的不足值等于文本行的大小。

读和写网络套接字。如果打开的文件对应于网络套接字,那么内部缓冲约束和较长的网络延迟会引起read和write返回不足值。对Unix管道调用read和write时,也有可能出现不足值,这种进程间的通信机制不在我们讨论的范围之内。

实际上,除了EOF,在读磁盘文件时,将不会遇到不足值,而且在写磁盘文件时,也不会遇到不足值。如果想创建简装的诸如web服务器这样的网络应用,就必须通过反复调用read和write处理不足值,直到所有需要的字节都传送完毕。

10.4 用RIO包健壮地读写

(1)RIO包会自动处理不足值。RIO提供了两类不同的函数

①无缓冲的输入输出函数。这些函数直接在存储器和文件之间传送数据,没有应用级缓冲,他们对将二进制数据读写到网络和从网络读写二进制数据尤其有用。

②带缓冲的输入函数。这些函数允许你高效地从文件中读取文本行和二进制数据,这些文件的内容缓存在应用级缓冲区内,类似于像printf这样的标准I/O函数提供的

(2)RIO的无缓冲的输入输出函数

①通过调用rio_readn和rio_writen函数,应用程序可以在存储器和文件之间直接传送数据

②rio_readn函数从描述符fd的当前文件位置最多传送n和字节到存储器位置usrbuf

③如果rio_readn和rio_writen函数被一个从应用信号处理程序的发放你会中断,那么每个函数都会手动地重启read或write。为了尽可能有较好地可移植性,允许被中断的系统调用,并在必要时重启他们

(3)RIO的带缓冲的输入函数

①一个文本行就是一个由换行符结尾的ASCII码字符序列。在Unix系统中,换行符(‘\n')与ASCII码换行符(LF)相同,数字值为0x0a

#include "csapp.h"

void rio_readinitb(rio_t *rp,int fd);//无返回

ssize_t rio_readlineb(rio_t *rp,void *usrbuf,size_t maxlen);

ssize_t rio_readnb(rio_t *rp,void *usrbuf,size_t n);//返回值:若成功为读得字节数,若EOF则为0,若出错为-1

ssize_t rio_readn(int fd,void *usrbuf,size_t n)

{

    size_t nleft=n;

    ssize_t nread;

    char *bufp=usrbuf;

    while(nleft>0){

        if((nread=read(fd,bufp,nleft))<0){

            if(errno==EINTR)

                nread=0;

            else

                return -1;

        }

        else if (nread==0)

            break;

        nleft-=nread;

        bufp+=nread;

    }

    return(n-nleft);

}       

 

ssize_t rio_writen(int fd,void *usrbuf,size_t n)

{

    size_t nleft=n;

    ssize_t nwritten;

    char *bufp=usrbuf;

    while(nleft>0){

        if((nwritten=write(fd,bufp,nleft))<=0){

            if(errno==EINTR)

                nwritten=0;

            else

                return -1;

        }

        nleft -=nwritten;

        bufp+=nwritten;

    }

    return n;

}

(4)RIO读程序核心:rio-read函数

static ssize_t rio_read(rio_t *rp,char *usrbuf,size_t n)

{

    int cnt;

    while(rp->rio_cnt<=0)//如果缓冲区为空,先调用函数填满缓冲区再读数据

    {

        rp->rio_cnt=read(rp->rio_fd,rp->rio_buf,sizeof(rp->rio_buf));//调用read函数填满缓冲区

        if(rp->rio_cnt<0)//排除文件读不出数据的情况

        {

            if(error != EINTR)

            {

                return -1;

            }

        }

        else if(rp->rio_cnt=0)

            return 0;

        else

            rp->rio_bufptr = rp->rio_buf;//更新现在读到的位置

    }

    cnt=n;

    if(rp->rio_cnt<n)

        cnt=rp->rio_cnt;//以上三步,将n与rp->rio_cnt中较小的值赋给cnt

    memcpy(usrbuf,rp->rio_bufptr,cnt);把读缓冲区的内容拷贝到用户缓冲区

    rp->rio_bufptr+=cnt;

    rp->rio_cnt-=cnt;

    return cnt;

}

 10.5 读取文件元数据

(1)应用程序能够通过调用stat和fstat函数,检索到关于文件的信息(元数据)

(2)文件类型

①普通文件:二进制或文本数据,宏指令:S_ISREG()

②目录文件:包含其他文件的信息,宏指令:S_ISDIR()

③套接字:通过网络和其他进程通信的文件,宏指令:S_ISSOCK()

10.6 共享文件

(1)内核用三个相关的数据结构来表示打开的文件

①描述符表

文件表

③v-node表
(2)三种打开文件的类型

①典型

②共享

③继承

 

 

 

 

10.7 I/0重定向

(1)Unix外壳提供了I/O重定向操作符,允许用户将磁盘文件和标准输入输出联系起来

(2)重定向使用dup2函数

10.8 标准I/O

(1)使用标准I/O的好处

因为在出UNIX的很多操作系统(包括Windows, linux)上都实现了此库,所有有利于软件的移植
(2)标准I/O的头文件
stdio.h
三个标准I/O流预定义指针:stdin, stdout, stderr
(Unix I/O: STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO)
(3)缓存
有缓存就会有延迟,即输出设备上的内容和缓存中的内容很可能不一样。可以调用fflush刷新缓存。
有多种缓存类型,可以调用下面的API来更改默认缓存类型。
setbuf,  setvbuf
setvbuf可以精确的说明缓存的类型。
fclose关闭流时也会刷新流。
当一个进程正常终止时(直接调用exit,或从main函数返回),则所有带未写缓存数据的标准I/O流都会被刷新,所有打开的标准I/O流都会被关闭。
遇到的问题
(1)标准I/O和Unix I/O的主要区别
参考资料
(1)教科书深入理解计算机系统
(2)博客园相关知识http://www.cnblogs.com/NeilHappy/archive/2012/12/04/2802033.html
http://www.cnblogs.com/uvsjoh/archive/2012/06/13/2547743.html
(3)百度http://book.2cto.com/201212/11759.html
 
 
 
posted @ 2015-11-08 12:00  20135226黄坤  阅读(319)  评论(0编辑  收藏  举报