20155317 《信息安全系统设计基础》第十三周周学习总结

20155317 《信息安全系统设计基础》第十三周周学习总结

一、UNIX I/O

    在UNIX系统中有一个说法,一切皆文件。所有的I/O设备,如网络、磁盘都被模型化为文件,而所有的输入和输出都被当做对相应文件的读和写来执行。这种将设备映射为文件的方式,允许UNIX内核引出一个简单、低级的应用接口,称为UNIX I/O,这使得所有的输入和输出都能以一种统一且一致的方式来执行。

  • 打开文件 打开文件操作完成以后才能对文件进行一些列的操作,打开完成过以后会返回一个文件描述符,它在后续对此文件的所有操作中标识这个文件,内核记录有关这个打开文件的所有信息。
  • 改变当前的文件位置。
  • 读写文件
  • 关闭文件 应用完成了对文件的访问之后,就通知内核关闭这个文件,内核释放文件打开时创建的数据结构,并将这个描述符恢复到可用的描述符池中。进程终止,内核也会关闭所有打开的文件并释放他们的存储器资源。

二、打开和关闭文件

    关于打开文件的基本操作,这里就不再累述,就是关于几个函数的解释,在上面的三篇文章中有解释。

    

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

 

    其中打开标志flags有三种基本标志:O_RDONLY、O_WRONLY、O_RDWR。也可以和其他三种(O_CREAT、O_TRUNC、O_APPEND)组合使用。mode参数指定了新文件的访问权限位。(这次终于看到完全的mode参数的使用方法了)

三、读和写文件

在系统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);  
}  

 

    关于在文件中定位使用的函数为lseek,在I/O库中使用的函数为fseek。
    size_t和ssize_t的区别:

 

unsign 和 没有unsign的区别:在前几次的袁征老师的密码分析学实验中,老师要求我们编写几个产生随机数的算法程序,我采取的是用斐波那契数列、线性同余等这样的数学书证明的方法去产生,但是在编写程序的时候,出现了负值的情况,也就是说产生的随机数是负值,也就是说出现了超出范围,可是在我的算法中随机值不会超过2的31次方,也就是说int或者long是完全够用的,为了避免出现上述的情况,我还特地用了long,但是还是出现了上述的错误:

最后经过查验,这并不是程序的思想导致的,这是由于C语言的编译器在进行有符号和无符号数的运算的时候所决定的。因为每个C语言编译器的版本不一样,其所能保证的范围也是不一样的,

后来经过修改,只要将其变成无符号的数便可以成功。

 

    有些情况下,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_readn和rio_writen。一个问本行的末尾都有一个换行符,那么像读取一个文本中的行数怎么办,使用read读取换行符这个方法不是很妥当,可以调用一个包装函数(rio_readineb),它从一个内部读缓冲区拷贝一个文本行,当缓冲区为空时,会自动地调用read重新填满缓冲区。也就是说,这些函数都是缓冲区操作而言的。

五、读取文件元数据

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

[cpp] view plain copy
 
#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\n",(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库将一个打开的文件模型化为一个流。对于一个程序而言,一个流就是一个指向FILE类型的结构的指针。类型为FILE的流是对文件描述符和流缓冲区的抽象。流缓冲区的目的和RIO读缓冲区的一样:就是使开销较高的UNIX I/O系统调用的数量尽可能的小。例如,当第一次调用getc时,库通过调用一次read函数来填充流缓冲区,然后将缓冲区总的第一个字节返回给应用程序。只要缓冲区还有未读的字节,接下来对getc的调用就能直接从流缓冲区得到服务。

八、重定向

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

 

九、课下练习

10.1

 

发现是库文件“csapp.h”的问题。经过修改后编译成功。

对于“csapp.h”这个头文件,可以从网址http://download.csdn.net/detail/tzasd89812/4206284上去下载,也可以用<stdio.h><fcntl.h><unistd.h>这三个头文件等效替代。我是选择的后种方法~

 


 10.2:

 

 10.3


 

10.4:

重定向标准输入(描述符0)到描述符5,我们将调用dup2(5,0)或者等价的dup2(5,STDIN_FILENO)。

10.5

代码托管

 

上周考试错题总结

 

( 单选题 | 1 分)
 

实验4:实验中加载驱动程序的Linux命令是(                    )

 

 
A.

lsmod

B.

rmmod

C.

insmod

D.

modprobe

正确答案: C
 
你的答案: A
这道题是有自己粗心导致的,没看清楚就是直接选了
 
 
( 单选题 | 1 分)
 

实验3中,在Ubuntu虚拟机中编译多线程程序时,gcc使用()选项

 
A.

-g

B.

-lthread

C.

-pthread

D.

-lpthread

正确答案: C
 
gcc 再进行编译的时候用的是pthread

 

实验1:mount -t nfs -o nolock 192.168.0.56:/root/share /host,其中的IP是()的IP

 
A.

Windows 宿主机

B.

Ubuntu虚拟机

C.

ARM实验箱

D.

以上都不对

正确答案: B
 
你的答案: C
这个在进行运算的时候,采用的是虚拟机进行处理的,所以IP是虚拟机的Ip

本周结对学习情况

- 20155301
- 结对照片
- 结对学习内容
    - XXXX
    - XXXX
    - ...

其他(感悟、思考等,可选)

我认为在linux操作系统中,最重要的就是对文件的操作以及处理,不管我们要做什么,要启用什么,在linu操作系统中,全部都是用文件进行模式化处理的,所以我认为这文件操作十分重要。

学习进度条

 代码行数(新增/累积)博客量(新增/累积)学习时间(新增/累积)重要成长
目标 5000行 30篇 400小时  
第一周 200/200 2/2 20/20  
第二周 300/500 2/4 18/38  
第三周 500/1000 3/7 22/60  
第四周 300/1300 2/9 30/90  

尝试一下记录「计划学习时间」和「实际学习时间」,到期末看看能不能改进自己的计划能力。这个工作学习中很重要,也很有用。 耗时估计的公式 :Y=X+X/N ,Y=X-X/N,训练次数多了,X、Y就接近了。

参考:软件工程软件的估计为什么这么难软件工程 估计方法

  • 计划学习时间:XX小时

  • 实际学习时间:XX小时

  • 改进情况:

(有空多看看现代软件工程 课件 软件工程师能力自我评价表)

参考资料

 



 

 

 

posted @ 2017-12-17 18:13  20155317wxw  阅读(221)  评论(0编辑  收藏  举报