博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

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

补充完成课上没有完成的内容(2分)

1 参考教材第十章内容

2 用Linux IO相关系统调用编写myod.c 用myod XXX实现Linux下od -tx -tc XXX的功能,注意XXX是文件名,通过命令行传入,不要让用户输入文件名

  • 不要把代码都写入main函数中

  • 要分模块,不要把代码都写入一个.c中

5 提交测试代码和运行结果截图, 提交调试过程截图,要全屏,包含自己的学号信息

命令行传参

在支持C语言的环境中,可以在程序开始执行时将命令行参数传递给程序。

当执行程序时,命令行参数(由shell逐一解析)通过两个入参提供给主函数main()。第一个参数int argc,表示命令行参数的个数。第二个参数char *argv[],是一个指向命令行参数的指针数组,每一参数又都是以空字符(null) 结尾的字符串。第一个字符串,亦即argv[0]指向的,(通常)是该程序的名称。argv中的指针列表以NULL指针结尾(即argv[argc]为NULL)。
main(int argc, char *argv[])

argc/argv参数机制的局限之一在于这些变量仅对main()函数可用。在保证可移植性的同时,为使这些命令行参数能为其他函数所用,必须把argv以参数形式传递给这些函数,或是设置一个指向argv的全局变量。

通过linux系统专有的/proc/PID/cmdline 文件可以读取任一进程的命令行参数,每个参数都以空(null)字节终止。(程序可以通过/proc/self/cmdline文件访问自己的命令行参数。)

系统调用

  • 文件描述符是一些小数值,可以通过它们访问的打开的文件设备,而有多少文件描述符可用取决于系统的配置情况。但是当一个程序开始运行时,它一般会有3个已经打开的文件描述符,就是
0:标准输入 

1:标准输出 

2:标准错误

那些数字(即0、1、2)就是文件描述符,因为在Linux上一切都是文件,所以标准输入(stdin),标准输出(stdout)和标准错误(stderr)也可看作文件来对待。

  • 用到的系统调用函数
  1. open系统调用

    函数原型:

    int open(const char *path, int oflags);

    int open(const char *path, int oflags, mode_t mode);

    使用的头文件有:

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

open建立了一条到文件或设备的访问路径,如果调用成功,返回一个可以被read、write等其他系统调用的函数使用的文件描述符,而且这个文件描述是唯一的,不与任何其他运行中的进程共享,在失败时返回-1,并设置全局变量errno来指明失明的原因。
2. read系统调用

函数原型:

size_t read(int fildes, void *buf, size_t nbytes);

使用的头文件:

#include<unistd.h>

read系统调用的作用是从与文件描述符相关的文件里读入nbytes个字节的数据,并把它们放到数据区buf中,返回读入的字节数,失败时返回-1。 如果顺利read()会返回实际读到的字节数,最好能将返回值与参数count作比较,若返回的字节数比要求读取的字节数少,则有可能读到了文件尾、从管道(pipe)或终端机读取,或者是read()被信号中断了读取动作。当有错误发生时则返回-1,错误代码存入errno中,而文件读写位置则无法预期。
3. close系统调用

函数原型:

int close(int fildes);

使用的头文件:

#include <unistd.h>

close函数的作用是终于文件描述符fildes一其对应的文件之间的关联。

遇到的问题:

代码运行结果会出现一行乱码,可能是代码仍存在问题,还未改好。

  • 最终运行截图:

学习教材附录A,第十章内容

输入/输出是在主存和外部设备之间拷贝数据的过程。
输入操作是从I/O设备拷贝数据到主存,输出操作是从主存拷贝数据到I/O设备。

10.1 Unix I/O

  • I/O设备:网络、磁盘和终端
    Unix I/O :将设备映射为文件的方式,允许Unix内核引出一个简单、低级的应用接口。
  • 描述符:打开文件时,内核返回一个小的非负整数。
  • Unix外壳创建的每个进程开始时都有三个打开的文件:标准输入(描述符为0)、标准输出(描述符为1)、标准错误(描述符为2)。
  • 改变当前的文件位置:文件位置为k,初始为0。
  • seek操作:显式地设置文件的当前位置为k.
  • EOF:是一个条件,而不是一个符号

10.2 打开和关闭文件

  • open函数:打开一个已存在的文件或者创建一个新文件
  • open函数将filename转换为一个文件描述符,并且返回描述符数字。返回的描述符总是在进程中当前没有打开的最小描述符。
O_ RDONLY :只读 
O_ WRONLY :只写 
O_ RDWR :可读可写
  • flag参数可以是一个或多个更多位掩码的或。
O_ CREAT:如果文件不存在,就创建它的一个截断的空文件
O_ TRUNC:如果文件已经存在,就截断它 
O_ APPEND:在每次写操作前,设置文件位置到文件的结尾处。

读和写文件

  • 应用程序是通过分别调用read和write函数来执行输入和输出的。
#include <unistd.h>
ssize_t read(int fd,void *buf,size_t n);
ssize_t write(int fd,const void *buf,size_t n);

10.4 用RIO包健壮地读写

  • RIO包的实质:I/O包
  • 应用程序通过调用rioreadn和riowritten函数可以在存储器和文件之间直接传送数据。
#include "csapp.h"
ssize_t rio_readn(int fd,void *usrbuf,size_t n);
ssize_t rio_writen(int fd,void *usrbuf,size_t n);

rio_ readn函数在遇到EOF时,只能返回一个不足值;

rio_ writen函数后局不会返回不足值。

10.5 读取文件元数据

  • 检索文件信息(元数据):应用程序能够通过调用stat和fstat函数
#include <unistd.h>
#include <sys/stat.h>
int stat(const char *filename,struct stat *buf);
int fstat(int fd,struct stat *buf);
  • 宏指令:根据st_mode成员来确定文件的类型。
在sys/stat.h中定义:

S_ ISREG():这是一个普通文件吗? 
S_ ISDIR():这是一个目录文件吗? 
S_ ISSOCK():这是一个网络套接字吗?

10.7 I/O重定向

  • Unix外壳提供了I/O重定向操作符,允许用户将磁盘文件和标准输入输出联系起来。

unix> ls > foo.txt

10.8 标准I/O

  • 标准I/O库将一个打开的文件模型化为一个流,一个流就是一个指向FILE类型的结构的指针。每个ANSIC程序开始都有三个打开的流stdin、stdout和stderr,分别对应于标准输入、标准输出、标准错误。
#include <stdio.h>
extern FILE *stdin;
extern FILE *stdout;
extern FILE *stderr;

学习中的问题和解决过程

  • 问题1:产生不足值的原因是什么?

  • 问题1解决方案:

    1、读时遇到EOF

    2、从终端读文本行

    3、读和写网络套接字

代码调试中的问题和解决过程

完成head,tail的使用,相关API的分析,伪代码,产品代码,测试代码的编写(3分)

通过查找man来学习这两个命令。

head命令

  • 命令功能:

    head 用来显示档案的开头至标准输出中,默认head命令打印其相应文件的开头10行。

  • 命令参数:

-q 隐藏文件名

-v 显示文件名

-c<字节> 显示字节数

-n<行数> 显示的行数
  • 命令格式:head [参数]... [文件]...
  • 使用实例:
  1. 显示文件的前n行:head -n 3 5217.txt
  2. 显示文件前n个字节:head -c 20 5217.txt
  3. 显示文件除后n个字节以外的内容:head -c -20 5217.txt

tail命令

  • 命令功能:

    用于显示指定文件末尾内容,不指定文件时,作为输入信息进行处理。常用查看日志文件。

  • 命令参数:

-f 循环读取

-q 不显示处理信息

-v 显示详细的处理信息

-c<数目> 显示的字节数

-n<行数> 显示行数

--pid=PID 与-f合用,表示在进程ID,PID死掉之后结束. 

-q, --quiet, --silent 从不输出给出文件名的首部 

-s, --sleep-interval=S 与-f合用,表示在每次反复的间隔休眠S秒 
  • 命令格式:

tail [ -f ] [ -c Number | -n Number | -m Number | -b Number | -k Number ] [ File ]tail [ -f ] [ -c Number | -n Number | -m Number | -b Number | -k Number ] [ File ]

  • 实例演示:
  1. 显示文件最后10行:tail 5217.txt
  2. 要指定从文件末尾开始读取的行数:tail -n 3 5217.txt

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

head命令 显示文件的前n行

代码运行截图:

tail命令 从第n行开始显示文件内容

代码运行截图:

代码托管

上周考试错题总结

结对及互评

点评模板:

  • 博客中值得学习的或问题:
    • xxx
    • xxx
    • ...
  • 代码中值得学习的或问题:
    • xxx
    • xxx
    • ...
  • 其他

本周结对学习情况

- [20155236](http://www.cnblogs.com/fcgfcgfcg/)
- 结对照片
- 结对学习内容
    I/O函数的使用
    应用程序可以通过open、close、lseek、read、write和stat这样的函数来访问Unix I/O。RIO函数:read和write的健壮的包装函数,自动处理不足值,为读文本行提供一种高效的带缓冲的方法。
    标准I/O函数:提供了Unix I/O函数的一个更加完整的带缓冲的替代品,包括格式化的I/O例程。是磁盘和终端设备I/O之选。
    套接字描述符:Unix对网络的抽象是一种称为套接字的文件类型,被称为套接字描述符。应用进程通过读写套接字描述符来与运行在其他计算机上的进程通信 。
    对流I/O限制是:跟在输出函数之后的输入函数,必须在其中间插入fflush、fseek、fsetpos或者rewind函数,后三个函数使用Unix I/O中的lseek函数来重置当前的文件位置。
    跟在输入函数之后的输出函数,必须在中间插入fseek、fsetpos或者rewind的调用,一个输出函数不能跟随在一个输入函数之后,除非该输入函数遇到了一个EOF。
    解决对流I/O限制的方法是:采用在每个输入操作前刷新缓存区这样的规则来满足。
    对同一个打开的套接字描述符打开两个流,一个用来读,一个用来写。
    对套接字使用lseek函数是非法的。
    在网络套接字上,使用RIO函数更常见。

学习进度条

代码行数(新增/累积) 博客量(新增/累积) 学习时间(新增/累积) 重要成长
目标 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

(虚拟机里statistics显示不了代码量)

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

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

  • 计划学习时间:XX小时

  • 实际学习时间:XX小时

  • 改进情况:

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

参考资料