zoukankan      html  css  js  c++  java
  • 20155335 俞昆《信息安全系统设计基础》第十三周

    一、Unix I/O 的定义

    将设备映射为文件的方式,允许UNIX内核引出一个简单、低级的应用接口,称为UNIX I/O.

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

    一个文件就是一个字节序列.

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

    1、打开文件: 一个应用程序通过要求内核来打开文件,内核返回一个小的非负整数(描述符),内核记录有关这个文件的所有的信息,应用程序只需要记住这个描述符。

    #include <sys/types.h>

    #include <sys/stat.h>

    <br>#include<fcntl.h>

    int open(char *filename,int flags,mode_t mode);

    //Returns: new file descriptor if OK, −1 on error

    其中打开标志有三个flags参数,即

    .  O_RDONLY: Reading only

    • .  O_WRONLY: Writing only

    • .  O_RDWR: Reading and writing

    2.关闭文件

       #include<unsitd.h>

       int close(int fd)

    3.读文件

    在系统I/O中读写文件用的系统函数为read()和write()函数来执行。

                #include <unistd.h>  

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

                 ssize_t write(int fd,void *buf,size_t n);  

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

    #include "csapp.h"  
      
    int main(void)   
    {  
        char c;  
      
        while(Read(STDIN_FILENO, &c, 1) != 0)   
        Write(STDOUT_FILENO, &c, 1);  
        exit(0);  
    } 
    size t 与ssize t的区别
    已知,size t和ssize t是在标准函数库中定义的。这个类型足以用来表示对象的大小。
    size t的真实类型与操作系统有关,在32位架构中被普遍定义为:
    typedef unsigned int size_t
    size_t 在32位架构上是4字节,在64位架构上是8字节,在不同架构上进行编译时需要注意几个问题。
    而int在不同架构下都是4字节,与size_t不同,int为带符号数,size_t为无符号数。
    有些情况下,read和write的传送的字节比应用程序要求的少,出现这种情况的原因是:
    读时遇到EOF,此时read返回0来发出EOF信号。
    从终端读入文本行,如果打开文件与终端相关联,那么每个read函数将以此传送一个文本行,返回的不足值等于文本行的大小
    读和写网络套接字,可能会出现阻塞现象。
    实际上,除了EOF,在读取磁盘文件时,将不会遇到不足时,而是写在磁盘文件时,也不会遇到不足值。然而,如果想创建健壮的网络应用,必须反复调用read和write处理不足值,直到所需要的字节传送玩毕。
    四、用RIO包健壮地读写
    这个包会处理上面的不足,RIO提供了方便,健壮和高效的I/O,提供了两类不同的函数。
    无缓冲的输入和输出函数直接在存储器和文件之间传送数据,在没有应用级缓冲,他们对将二进制数据读写到网络和从网络读写二进制数据尤其有用。
    带缓冲的输入函数如下:
    ssize_t rio_readn(int fd,void *usrbuf,size_t n);   
    ssize_t rio_writen(int fd,void *usrbuf,size_t n); 
    对同一个描述符,可以任意交错的调用rio_read和rio_writen.一个文本行的末尾都有一个换行符,读取文本的行数怎么办,使用read读取换行符这个方法不是很妥当,可以调用一个包装函数(rio_readlieb),

    五.读取文件元数据
    应用程序能够通过调用stat和fstat函数股检索到关于文件的信息(有时称为文件的元数据)
    #include <sys/stat.h>  
    #include <unistd.h>  
    int stat(const char *filename,struct stat *buf);  
    int fstat(int fd,struct stat *buf);
    若成功,返回0,若出错则为-1,stat以一个文件名为输入,并且填充buf结构体。fstat函数只不过是以文件描述符而不是文件名作为输入。
    struct stat {  
    #if defined(__ARMEB__)  
        unsigned short st_dev;  
        unsigned short __pad1;  
    #else  
        unsigned long  st_dev;  
    #endif  
        unsigned long  st_ino;  
        unsigned short st_mode;  
        unsigned short st_nlink;  
        unsigned short st_uid;  
        unsigned short st_gid;  
    #if defined(__ARMEB__)  
        unsigned short st_rdev;  
        unsigned short __pad2;  
    #else  
        unsigned long  st_rdev;  
    #endif  
        unsigned long  st_size;  
        unsigned long  st_blksize;  
        unsigned long  st_blocks;  
        unsigned long  st_atime;  
        unsigned long  st_atime_nsec;  
        unsigned long  st_mtime;  
        unsigned long  st_mtime_nsec;  
        unsigned long  st_ctime;  
        unsigned long  st_ctime_nsec;  
        unsigned long  __unused4;  
        unsigned long  __unused5;  
    };  
    其中st_size成员包含了文件的字节大小。st_mode为文件访问许可位。
    UNIX提供的宏指令根据st_mode成员来确定文件的类型:S_ISREG(),这是一个普通文件么;S_ISDIR(),这是一个目录文件么;
    S_ISSOCK()这是一个网络套接字么。使用一下这个函数
    #include <stdio.h>  
    #include <stdlib.h>  
    #include <string.h>  
    #include <sys/stat.h>  
    #include <sys/types.h>  
    #include <unistd.h>  
    int main()  
    {  
        int fd,size;  
        struct stat buf_stat;  
        memset(&buf_stat,0x00,sizeof(buf_stat));  
        fd=stat("stat.c",&buf_stat);  
            printf("%d
    ",(int)buf_stat.st_size);  
        return 0;  
        }  
    六.共享文件

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

    • 描述符表(descriptor table)每个进程都有它独立的描述符表,它的表项是由进程打开的文件描述符来索引的。每个打开的描述符表项指向文件表中的一个表项。
    • 文件表(file table)  打开文件的描述符表项指向问价表中的一个表项。所有的进程共享这张表。每个文件表的表项组成包括由当前的文件位置、引用计数(既当前指向该表项的描述符表项数),以及一个指向v-node表中对应表项的指针。关闭一个描述符会减少相应的文件表表项中的应用计数。内核不会删除这个文件表表项,直到它的引用计数为零。
    • v-node表(v-node table)同文件表一样,所有的进程共享这张v-node表,每个表项包含stat结构中的大多数信息,包括st_mode和st_size成员。
    • 描述符1和4通过不同的打开文件表表项来引用两个不同的文件。这是典型的情况,没有共享文件,并且每个描述符对应一个不同的文件。

            多个描述符也可以通过不同的文件表表项来应用同一个文件。如果同一个文件被open两次,就会发生上面的情况。关键思想是每个描述符都有它自己的文件位置,所以对不同描述符的读操作可以从文件的不同位置获取数据。

            父子进程也是可以共享文件的,在调用fork()之前,父进程如第一张图,然后调用fork()之后,子进程有一个父进程描述符表的副本。父子进程共享相同的打开文件表集合,因此共享相同的文件位置。一个很重要的结果就是,在内核删除相应文件表表项之前,父子进程必须都关闭了他们的描述符。   

    七.标准I/O

            标准I/O是ANSI C建立的一个标准I/O模型,是一个标准函数包和stdio.h头文件中的定义,具有一定的可移植性。标准I/O库处理很多细节。例如缓存分配,以优化长度执行I/O等。标准的I/O提供了三种类型的缓存。

     

    (1)全缓存:当填满标准I/O缓存后才进行实际的I/O操作。  (2)行缓存:当输入或输出中遇到新行符时,标准I/O库执行I/O操作。  (3)不带缓存:stderr就是了。

    八.重定向

    • I/O重定向操作符,允许用户将磁盘文件和标准输入输出联系起来。unix> ls > foo.txt
    • I/O重定向是依靠dup2函数工作的。dup2函数拷贝描述符表表项oldfd到描述符表项newfd,覆盖描述符表表项newfd以前的内容。如果newfd已经打开,dup2会在拷贝oldfd之前关闭newfd。

     

     

     

    
    
    
    
    
    
     
    
    






     

    4.

  • 相关阅读:
    Python学习杂记_2_格式化字符串的一些操作
    Python学习杂记_1_PyCharm使用的一些收获
    autolayout sizeclass 资料集锦
    据说这个是获得当前的控制器方法,没试过
    Mac下搭建php开发环境【转】
    搜索栏会消失 uisearchbar 狂点消失的问题解决
    mac下XAMPP服务器配置多站点配置局域网配置 (转)
    在 Xcode 6 中使用矢量图( iPhone 6 置配 UI)
    收到远程通知,怎么区分是点击通知栏提醒进去的还是在foreground收到的通知?
    开发经验之状态机思想,分别使用了swift,OC,C,PHP语言实现
  • 原文地址:https://www.cnblogs.com/xieboke/p/8053356.html
Copyright © 2011-2022 走看看