郝博雅

导航

2017-2018-1 20155205 《信息安全系统设计基础》第四周学习总结

2017-2018-1 20155205 《信息安全系统设计基础》第四周学习总结

课上实践--myod-系统调用版本

  • 要求:

    1.参考教材第十章内容
    2.用Linux IO相关系统调用编写myod.c 用myod XXX实现Linux下od -tx -tc XXX的功能,注意XXX是文件名,通过命令行传入,不要让用户输入文件名
    3.不要把代码都写入main函数中
    4.要分模块,不要把代码都写入一个.c中
    5.提交测试代码和运行结果截图,提交调试过程截图,要全屏,包含自己的学号信息
    6.课上上传代码到码云
    

head,tail的相关学习

相关API的分析

  • head
    • 语法:head [参数] 文件
    • 命令功能:head用来显示档案的开头至标准输出当中,默认head命令打印其相应文件的开头10行。

 -c<字符数>:指定显示头部内容的字符数
-n<数字>:指定显示头部内容的行数

来自: http://man.linuxde.net/head

  • tail
    • 功能:显示指定文件的后若干行。
    • 语法: tail [+ / - num ] [参数] 文件
    • tail命令中各个选项的含义为:+num 从第num行以后开始显示。-num 从距文件尾 num行处开始显示。如果省略 num参数,系统默认值为 10。

  • 使用tail命令的-f选项可以方便的查阅正在改变的日志文件,tail -f filename会把filename里最尾部的内容显示在屏幕上,并且不但刷新,使你看到最新的文件内容。

伪代码,产品代码,测试代码的编写

  • myhead

伪代码:

打开文件;
循环按字符读入文件,每读一个换行符计数器加一;
读满10个换行符停止输出;
结束程序

产品代码:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>

int main(int argc,char *argv[])
{

    int fd,c=0;
    char ch;
    fd=open(argv[1],O_RDONLY,0);
    if(fd==-1)
    {
        printf("出现错误!");
        exit(1);
    }
    while(read(fd,&ch,1)!=0)
    {
        printf("%c",ch);
        if(ch=='\n') c++;
        if(c==10) break;
    }//方法参考p599图10-2程序,将while循环中的write(fd,&ch,1)改为从屏幕输出字符,并加入了判断。
    close(fd);
    exit(0);
}

  • tail

伪代码:

打开文件;
循环按字符第一次读入文件,统计总共的行数;
再次读入文件,当行数>=总行数-10时输出字符;
结束程序

产品代码:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

int main(int argc,char *argv[])
{

    int fd1,fd2,c=0,n=0;
    char ch;

    fd1=open(argv[1],O_RDONLY,0);
    if(fd1==-1)
    {
        printf("出现错误!");
        exit(1);
    }
    while(read(fd1,&ch,1)!=0)
      {
          if(ch=='\n') c++;
       }
    close(fd1);

    fd2=open(argv[1],O_RDONLY,0);
    while(read(fd2,&ch,1)!=0)
      {
          if(ch=='\n') n++;
          if(n>=c-10)printf("%c",ch);
       }

    close(fd2);
    exit(0);
}

教材学习中的问题和解决过程

  • 问题1:练习题10.1程序的输出为什么是3?即打开文件和文件描述符的关系是什么?

  • 问题1解决方案:

    查阅资料后有段话解释了我的问题:

在Linux系统中一切皆可以看成是文件,文件又可分为:普通文件、目录文件、链接文件和设备文件。文件描述符(file descriptor)是内核为了高效管理已被打开的文件所创建的索引,其是一个非负整数(通常是小整数),用于指代被打开的文件,所有执行I/O操作的系统调用都通过文件描述符。程序刚刚启动的时候,0是标准输入,1是标准输出,2是标准错误。如果此时去打开一个新的文件,它的文件描述符会是3,再调用open 就会返回4。

而且我了解到

每个进程在Linux内核中都有一个task_struct结构体来维护进程相关的 信息,称为进程描述符(Process Descriptor),而在操作系统理论中称为进程控制块 (PCB,Process Control Block)。task_struct中有一个指针(struct files_struct *files; )指向files_struct结构体,称为文件 描述符表,其中每个表项包含一个指向已打开的文件的指针,如下图所示。

用户程序不能直接访问内核中的文件描述符表,而只能使用文件描述符表的索引 (即0、1、2、3这些数字),这些索引就称为文件描述符(File Descriptor),用int 型变量保存。 当调用open 打开一个文件或创建一个新文件时,内核分配一个文件描述符并返回给用户程序,该文件描述符表项中的指针指向新打开的文件。当读写文件时,用户程序把文件描述符传给read 或write ,内核根据文件描述符找到相应的表项,再通过表项中的指针找到相应的文件。

这就加深了我对打开文件和文件描述符的理解,也知道了家庭作业10.6的答案:因为调用了两次open函数,所以返回值是4,然后调用close释放了描述符4,再次调用open返回值又是4了,所以输出是4。

自己敲代码验证了一下:

代码学习中的问题和解决过程

  • 问题1:运行程序时遇到了头文件csapp.h错误的情况
  • 问题1解决方案:csapp.h其实就是一堆头文件的打包,在http://csapp.cs.cmu.edu/public/code.html 这里可以下载。《深入理解计算机系统》配套网站
    下载并解压后(以 root 身份登录)应该是一个code的文件夹,在其子文件夹include和src中分别可以找到csapp.h和csapp.c两个文件,把这两个文件拷贝到文件夹/usr/include里面,并在csapp.h文件中 #endif 之前加上一句 #include<csapp.h> ,然后编译时在最后加上 “-lpthread” 例如:gcc main.c -lpthread 就可以编译了。

代码链接

参考资料

posted on 2017-10-15 22:19  郝博雅  阅读(469)  评论(9编辑  收藏  举报