zoukankan      html  css  js  c++  java
  • 信息安全系统设计基础第九周学习总结

    第十章 系统级I/O

    • 输入/输出(I/O)是在主存和外部设备(如磁盘驱动器、终端和网络)之间拷贝数据的过程。
    • 输入就是从I/O设备拷贝数据到主存,而输出就是从主存拷贝数据到I/O设备。
    • 所有语言的运行时系统都提供执行I/O的较高级别的工具。例如,ANSI C提供标准I/O库,包含像printf和scanf这样执行带缓冲区的I/O函数。C++语言用它的重载操作符<<(输出)和>>(输入)提供了类似的功能。在UNIX系统中,是通过使用由内核提供的系统级Unix I/O函数来实现这些比较高级的I/O函数的。

    10.1 Unix I/O

    • 每个unix文件都是一个m字节的序列;所有I/O设备如网络、磁盘和终端都被模型化为文件,而输入和输出就是对这些文件的读写操作。

    • Unix系统中输入输出的操作:

      打开文件:一个应用程序通过要求内核打开相应的文件,来宣告它想要访问一个I/O设备,内核返回一个小的非负整数,叫做描述符。unix系统创建每个进程的时候都有三个打开的文件:标准输入;标准输出,标准错误。

      改变当前的文件位置。对于每个打开的文件,内核保持着一个文件位置k(从文件开头起始的字节偏移量)。

      读写文件。读操作就是从文件拷贝n>0个字节到存储器,从当前文件位置k开始,然后将k增加到k+n。

      关闭文件。应用通知内核关闭这个文件;作为响应,内核释放文件打开时创建的数据结构,并将这个描述符恢复到可用的描述符池当中。

    10.2 打开和关闭文件

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

      `#include  <sys/type.h>'
      
      `#include <sys/stat.h>'
      
      `#include <fcntl.h>`
      
      
      `int open(char  *filename,  int flags, mode_t  mode);`
      
              '返回:若成功则为新文件描述符,若出错为-1.`
      
    • open函数将filename转换为一个文件描述符,并且返回描述符数字。返回的描述符总是在进程中当前没有打开的最小描述符。flags参数指明了进程打算如何访问这个文件:

      • O_RDONLY:只读。
      • O_WRONLY:只写。
      • O_RDWR:可读可写。
    • flags参数也可以是一个或者更多位掩码的或,提供一些额外的指示:

       -O_CREAT:如果文件不存在,就创建他的一个截断的(truncated)(空)文件。
       -O_TRUNC:如果文件已经存在,就截断它。
       -O_APPEND:在每次写操作前,设置文件位置到文件的结尾处。
      
    • 打开文件:

      fd = Open("文件名",flag位——表示访问方式及额外提示,mode参数);//出错的时候返回-1

      • mode参数指定新文件的访问权限位。作为上下文的一部分,每个进程都有一个umask;当进程通过带某个带mode参数的open函数用来创建一个新文件的时候,文件的访问权限位被设置为mode & ~umask。 以上为访问权限位。在sys/stat.h中定义。
    • 关闭文件:

    int close(int fd);//若成功则返回0,不成功则为-1。

    10.3 读和写文件

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

    #include <unistd.h>

    `ssize_t read(int fd,void *buf,size_t n);//

              返回值:成功为读的字节数,若EOF为0,出错为-1`
    

    ssize_t write(int fd,const void *buf,size_t n);// 返回值成功为写的字节数,出错为-1

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

      ssize_t read(int fd,void *buf,size_t n);//成功则返回n;EOF返回0;出错返回-1

    read函数从描述符为fd的当前文件位置拷贝最多n个字节到存储器位置buf。 - 在某些情况下,read和write传送的字节比应用程序要求的要少。出现这种情况的可能的原因有:

    读时遇到EOF。假设该文件从当前文件位置开始只含有20个字节,而应用程序要求我们以50个字节的片进行读取,这样一来,这个read的返回的值是20,在此之后的read则返回0。
    
    从终端读文本行。如果打开的文件是与终端相关联的,那么每个read函数将一次传送一个文本行,返回的不足值等于文本行的大小。
    
    读和写socket。如果打开的文件对应于网络套接字,那么内部缓冲约束和较长的网络延迟会导致read和write返回不足值。
    

    10.4 用RIO包健壮地读写

    RIO提供了两类不同的函数:

    无缓冲的输入输出函数
    带缓冲的输入函数
    

    无缓冲的输入输出函数:

    • 直接在存储器和文件之间传送数据(允许被中断的字节调用,并在必要的时候重启它们)。

      `ssizet riowriten(int fd,const void *usrbuf,size_t n);

      ssizet riowriten(int fd,const void *usrbuf,size_t n);`

    rio__writen函数遇到EOF的时候返回0;

    rio__readn遇到EOF的时候返回不足值(即 不足n的那个部分的字节数)。

    • 带缓冲的输入函数:

      允许用户高效地从文件中读取文本行和二进制数据(之前是一次读一个字节,应用这个函数之后,可以一次读一行函数)。 原理:

        函数从内部缓冲区中拷贝一个文本行,当缓冲区变空的时候,会自动地调用read重新填满缓冲区。
      

    rio的带缓冲的输入函数详解

    • rioreadinitb(riot *rp,int fd);

      每打开一个描述符都会调用一次该函数,它将描述符fd和地址rp处的类型为rio_t的缓冲区联系起来。

    • rioreadnb(riot *rp,void *usrbuf,size_t n) ;

      从文件rp中最多读n个字节到存储器位置usrbuf。对同一描述符,rioreadnb和rioreadlineb的调用可以交叉进行。

    • ssizet readlineb(riot *rp,void *usrbuf,size_t maxlen);

      从文件rp中读取一个文本行(包括结尾的换行符),将它拷贝到存储器位置usrbuf,并用空字符来结束这个文本行。

    • RIO读程序的核心是rioread函数,rioread函数可以看成是Unix read函数的带缓冲区的版本。当调用rioread要求读取n个字节的时候,读缓冲区内有rp->riocnt个未读的字节。如果缓冲区为空的时候,就会调用read系统函数去填满缓冲区。这个read调用收到一个不足值的话并不是一个错误,只不过读缓冲区的是填充了一部分。

    • 一旦缓冲区非空,rioread就从读缓冲区拷贝n和rp->riocnt中较小值个字节到用户缓冲区,并返回拷贝字节的数目。
    • 对于应用程序来说,rioread和系统调用read有着相同的语义。出错时返回-1;在EOF时,返回0;如果要求的字节超过了读缓冲区内未读的字节的数目,它会返回一个不足值。rioreadlineb函数多次调用rio_read函数。每次调用都从读缓冲区返回一个字节,然后检查这个字节是否是结尾的换行符。
    • rio_readlineb函数最多读取(maxlen-1)个字节,余下的一个字节留给结尾的空字符。超过maxlen-1字节的文本行被截断,并用一个空字符结束。

    10.5 读取文件元数据

    • 应用程序能够通过调用stat和fstat函数,检索到关于文件的信息。
    • 函数格式:

      `#include <unistd.h>

      #include <sys/stat.h>

      int stat(cost char *filename,struc sta *buf);

      int fstat(int fd,struct stat *buf);`

    • 这两个函数都需要填写stat结构体的各个成员。这里举两个例子:stsize包含了文件的字节数大小;stmode则编码了文件访问许可位和文件类型(目录文件:包含关于其他文件的信息;套接字是一种用来通过网络与其他进程通信的文件)。
    • 目录文件包含关于其他文件的信息。套接字是一种用来通过网络与其他进程通信的文件。Unix提供的宏指令根据st_mode成员来确定文件的类型。这些宏的一个子集如下:

    10.6 共享文件

    • 内核用三个相关的数据结构来表示打开的文件:

      • 描述符表:每个打开的描述符表项指向文件表中的一个表项
      • 文件表:所有进程共享这张表,每个表项包括文件位置,引用计数,以及一个指向v-node表对应表项的指针
      • v-node表:所有进程共享这张表,包含stat结构中的大多数信息
    • 三种打开文件的类型:

      典型:描述符各自引用不同的文件,没有共享
      文件表:所有进程共享这张表,每个表项包括文件位置,引用计数,以及一个指向v-node表对应表项的指针
      继承:子进程继承父进程打开文件。调用fork后,子进程有一个父进程描述符表的副本,父子进程共享相同的打开文件表集合,因此共享相同的文件位置
      

    10.7 i/o重定向

    • Unix外壳提供了I/O重定向操作符,允许用户将磁盘文件和标准输入输出联系起来。
    • I/O重定向的工作方式: 一种是使用dup2函数。

    `include <unisted.h>

    int dup2(int oldfd, int newfd);`

    • dup2函数拷贝描述符表表项oldfd到描述符表表项newfd,覆盖描述符表表项newfd以前的内容。如果newfd已经打开了,dup2会在拷贝oldfd之前关闭newfd。

    10.8 标准 I/O

    • ANSI C定义了一组高级输入输出函数,称为标准I/O库。提供了打开和关闭文件的函数(fopen和fclose),读和写字节的函数(fread和fwrite),读和写字符串的函数(fgets和fputs),格式化I/O函数(scanf和printf)
    • 标准I/O库将一个打开的文件模型化为一个流。一个流就是一个指向FILE类型的结构的指针
    • 每个ANSI C程序开始时都有三个打开的流stdin、stdout、stderr,分别对应标准输入、标准输出、标准错误

    -类型为FILE的流是对文件描述符和流缓存区的抽象

    10.9 综合:我该使用哪些i/o函数

    这一章讨论过的各种I/O包

    • 标准I/O流,从某种意义上来说是全双工的,因为程序能够在同一个流上执行输入和输出。
    • 建议在网络套接字上不要使用标准I/O函数来进行输入和输出。而要使用健壮的RIO函数。

    10.10 小结

    • Unix提供了少量的系统级函数,它们允许应用程序打开、关闭、读和写文件,提取文件的元数据,以及执行I/O重定向。Unix的读和写操作会出现不足值,应用程序必须能正确地预计和处理这种情况。应用程序不应直接调用unⅸ I/O函数,而应该使用RIO包,RIO包通过反复执行读写操作,直到传送完所有的请求数据,自动处理不足值。
    • Unix内核使用三个相关的数据结构来表示打开的文件。描述符表中的表项指向打开文件中的表项,而打开文件表中的表项又指向v-node表中的表项,每个进程都有它自己单独的描述符表,而所有的进程共享同一个打开文件表和v-node表,理解这些结构的一般组成就能使我们清楚地理解文件共享和I/O重定向。
    • 标准I/O库是基于Unix I/O实现的,并提供了一组强大的高级I/O例程,对于大多数应用程序而言,标准I/O更简单,是优于Unix I/O的选择。然而,因为对标准I/O和网络文件的一些相互不兼容的限制,Unix I/O比标准I/O更适用于网络应用程序。

    10.11 心得体会

    这一章其实看起来内容挺少,但我觉得是真正的精髓在这里面,是知啊前学过的总结之后上升的一个很大的层次,所以很多代码看懂都要很费劲,要时不时的去看之前的内容,一边复习,一边学习这一章。。。 遇到的问题其实一直都是虚拟机打不开的问题,之前老师发过的别人的解决办法的博客我去看了也无法解决,找了很多大神都没找到问题,其中有位大神就帮我弄的时候电脑还遭遇了很大的问题,就是硬盘损坏,花了400块钱才换了新的硬盘,这都是10月份的事情了,至今都不敢在动虚拟机。。

  • 相关阅读:
    raspberry pi (树莓PI)使用socket向PC发送视频流
    树莓PI交叉编译BOOST库(asio网络例子)
    远程调试树莓PI
    opencv车速检测
    屏蔽同步(JAVA)
    linux常用命令记录
    虚拟机中Ubuntu设置固定IP方法
    java笔记01-反射
    java笔记00-目录
    mysql由于外键关联无法删除数据
  • 原文地址:https://www.cnblogs.com/20135239-yxlm/p/4947359.html
Copyright © 2011-2022 走看看