• 26、深入理解计算机系统笔记,系统级I/O


    1、一个unix文件就是一个m字节的序列(b0b1b2...bm-1)。所有的IO设备,如网络,磁盘,终端,都被模型化为文件,而所有的输入和输出都被当作对相应文件的读和写来执行。

    2、所有的输入和输出都被当作统一的方式来处理:

    1)打开文件。一个应用程序通过要求内核打开相应的文件,来宣告它想要访问一个IO设备。内核返回一个小的非负整数,叫做描述符,它在后续对此文件的所有操作中标识这个文件。内核记录这个打开文件的所有信息,而应用程序只需记住这个描述符。

    Unix创建的每个进程开始都有三个打开的文件:标准输入(描述符为0),标准输出(描述符1),标准错误(描述符为2)。头文件unistd.h中定义了相关常量。

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

    3)内核释放文件打开时创建的数据结构,并恢复描述符到可获得描述符池中。

    3、相关函数

    open,close,read,write。具体定义可以参见man手册,或相关网页,或本书11.3

    1)某些情况下,原始的read,write传送的字节比应用程序要求的要少,这些不足值(short count)不一定是错误(意为,比如read函数参数要读5个字节,结果只读了3个字节,即小于5),下面的情况下将可能发生不足值:

    1)读时遇到EOF

    2)从终端读文本行。

    3)读和写网络套接字。

    为了避免不足值问题(健壮程序的需求,如Web服务器这样的网络应用),就需要处理不足值。本书作者11.4节开发了Rio包满足这个情况。

    4、函数是线程安全的:它在同一个描述符上可以被交替地调用。

    5、元数据:关于文件的信息,如创建时间,修改时间,metadata。可以调用statfstat函数。

    6、对于内核而言,文件文件和二进制文件毫无区别。

    7、共享文件

    内核用三种相关的数据结构来表示打开的文件。

    1)描述符表:它的表项由进程打开的文件描述符来索引的。

    2)文件表:打开文件的集合是一张文件表来表示的,所有的进程共享这张表。

    3)v-node表:同文件表一样,所有的进程共享这张v-node表。每个表项包含stat结构中的大部分信息,如文件大小等。

    wps_clip_image-27848ScreenShot008

    多个描述符也可以通过不同的文件表项来引用同一个文件。

    wps_clip_image-25864

    下图展示一个fork创建子进程的情况:子进程有一个父进程描述符的副本;父子进程共享相同的打开文件表集合,因此共享相同的文件位置。注意点:在内核删除相应文件表表项前,父子进程必须都关闭了它们的描述符。

    wps_clip_image-9282

    8、IO重定向

    unix > ls > foo.txt

    实际是dup2函数(one case)。dup2函数对文件描述符表项进行重定位。

    wps_clip_image-16150

    9、标准IO

    标准函数如fopen,fclose,fread,fwrite,fgets,fputs,scanf,printf

    标准IO库将一个打开的文件模型化为一个流,对于程序员来说,一个流就是一个指向类型为FILE结构的一个指针。每个ANSI C程序开始都有三个打开的流stdin,stdout,stderr,分别对应于标准输入、输出、错误。

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

    10、示例图

    wps_clip_image-13246

    11、标准IO流,从某种意义上而言是全双工的,因为程序能够在同一个流上执行输入和输出。但是有一些限定:

    1)限定1:输入函数跟有输出函数之后。如果中间没有fflush,fseek,fsetposrewind的调用,一个输入函数不能跟随在一个输出函数之后。fflush清空与流相关的缓冲区,后三个函数使用unix IO lseek函数来重置当前文件的位置。

    2)限定2:输出函数跟有输入函数之后。情况类同上。

        这些限定给网络应用带来一个问题:因为对套接字使用lseek是非法的。用Rio包可以解决这个问题。用sprintf把输出格式化一个字符串,通过rio_writen输出,傅rio_readlineb来读一行,用scanf来从文本中提取不同的字段。

  • 相关阅读:
    Redis的高级应用——数据安全
    [转]C#多线程和线程池
    详解从面向接口编程到依赖注入
    Java Servlet 配置
    Java Servlet 3.0 新特性
    [转]C#中的委托和事件
    iReport5.6.0使用说明
    Visual Studio 2015 官方下载及密钥
    Java Swing 托盘闪烁Demo实例
    Win7 利用批处理文件结束进程
  • 原文地址:https://www.cnblogs.com/mydomain/p/2096950.html
Copyright © 2020-2023  润新知