20155322 2017-2018-1《信息安全系统设计》第四周学习总结
20155322 2017-2018-1《信息安全系统设计》第四周学习总结
[博客目录]
一、教材学习内容总结
本周学习的内容为第十章
Linux提供了一些基于UnixI/O模型的系统级函数,它们允许应用程序打开、关闭、读写文件,提取文件元数据,以及执行I/O重定向。标准I/O库是基于UnixI/O库实现的,并提供一组强大的高级I/O例程。标准I/O比UnixI/O更简洁,但是对于网络应用程序,Unix的更适合,下面是一些详细的介绍:
-
linux基本I/O接口
在Linux中,read 和 write 是基本的系统级I/O函数。当用户进程使用read 和 write 读写linux的文件时,进程会从用户态进入内核态,通过I/O操作读取文件中的数据。内核态(内核模式)和用户态(用户模式)是linux的一种机制,用于限制应用可以执行的指令和可访问的地址空间,这通过设置某个控制寄存器的位来实现。进程处于用户模式下,它不允许发起I/O操作,所以它必须通过系统调用进入内核模式才能对文件进行读取。 -
RIO包
RIO,全称Robust I/,即健壮的IO包。它提供了与系统I/O类似的函数接口,在读取操作时,RIO包加入了读缓冲区,一定程度上增加了程序的读取效率。另外,带缓冲的输入函数是线程安全的。RIO包中有专门的数据结构为每一个文件描述符都分配了相应的独立的读缓冲区,这样不同线程对不同文件描述符的读访问也就不会出现并发问题(然而若多线程同时读同一个文件描述符则有可能发生并发访问问题,需要利用锁机制封锁临界区)。 -
标准IO库
绝大部分的系统都提供了C接口的标准IO库,与RIO包相比,标准IO库有更加健全的,带缓冲的并且支持格式化输入输出。标准IO和RIO包都是利用read, write等系统调用实现的。标准IO操作的对象与Unix I/O的不太相同,标准IO接口的操作对象是围绕流(stream)进行的。对于大多数应用程序而言,标准IO更简单,是优于Unix I/O的选择。然而在网络套接字的编程中,建议不要使用标准IO函数进行操作,而要使用健壮的RIO函数。RIO函数提供了带缓冲的读操作,与无缓冲的写操作(对于套接字来说不需要),且是线程安全的。 -
I/O重定向
在Unix系统中,每个进程都有STDIN、STDOUT和STDERR这3种标准I/O,它们是程序最通用的输入输出方式。几乎所有语言都有相应的标准I/O函数,比如,C语言可以通过scanf从终端输入字符,通过printf向终端输出字符。熟悉Shell的人可以方便地对Shell命令进行I/O重定向,比如 find -name "* .java" >testfile.txt 把当前目录下的Java文件列表重定向到testfile.txt。
- 别出心裁的Linux系统调用学习法
- man -k key1 | grep key2| grep 2 : 根据关键字检索系统调用
- grep -nr XXX /usr/include :查找宏定义,类型定义
课堂练习
- 练习题目:用Linux IO相关系统调用编写myod.c 用myod XXX实现Linux下
od -tx -tc XXX
的功能,注意XXX是文件名,通过命令行传入,不要让用户输入文件名。 - 使用系统调用函数
open
、read
、close
,学习使用方法并实践。 - 实践操作:在原来
Myod5322_V2.0.c
代码的基础上修改,替换了原本使用的fopen/fgets/fclose函数,增加了系统调用函数所需头文件,遇到的问题见代码调试中。 - 相关代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
void tc(int i,int j, char ch[]);
void tx(int i,int j, char ch[]);
void run(int fd,int flag[]);
int main(int argc,char *argv[])
{
int i;
int flag[2];
int fd;
fd=open(argv[argc-1],O_RDONLY,0);
if(fd==-1){
printf("ERROR!\n");
exit(0);
}
for(i=1;i<argc-1;i++){
if(strcmp(argv[i], "-tc")==0){
flag[i-1] = 1;
}
if(strcmp(argv[i], "-tx1")==0){
flag[i-1] = 1;
}
}
//FILE *file=fopen(argv[argc-1],"r");
run(fd,flag);
close(fd);
return 0;
}
void run(int fd,int flag[]){
char ch[18];
int i=0,j=0;
if(flag[0] + flag[1] == 2) {
while(read(fd,&ch,17)!=NULL){
tc(i,j,ch);
j++;
tx(i,j,ch);
printf("\n");
}
j++;
printf("%07o",16*(j-1)+i);
printf("\n");
}
else if(flag[0] == 1) {
while(read(fd,&ch,17)!=NULL){
tc(i,j,ch);
j++;
//tx(i,j,ch);
printf("\n");
}
j++;
printf("%07o",16*(j-1)+i);
printf("\n");
}
else if(flag[1] == 1){
while(read(fd,&ch,17)!=NULL){
tx(i,j,ch);
j++;
printf("\n");
}
j++;
printf("%07o",16*(j-1)+i);
printf("\n");
}
//fclose(file);
}
void tc(int i,int j, char ch[])
{
printf("%07o",16*j);
j++;
for(i=0;i<16;i++)
{
if(ch[i]=='\n')
{ i++;
putchar(' ');
printf("\\n");
}
if(ch[i]=='\0')
break;
putchar(' ');
putchar(' ');
printf("%c", ch[i]);
putchar(' ');
}
printf("\n");
}
void tx(int i,int j, char ch[])
{
printf(" ");
for(i=0;i<16;i++)
{
if(ch[i]=='\n')
{ i++;
printf("%3x ",'\n');
}
if(ch[i]=='\0')
break;
printf("%3x ",ch[i]);
}
}
实现截图:
二、教材学习中的问题和解决过程
- 问题1:对于IO的理解,标准IO和文件IO有什么区别?
- 解决:通过百度搜索,我在CSDN上找到一篇博客很详细的解释了这个问题:标准IO与文件IO 的区别
- 总结:
- 文件IO是一般所说的低级I/O——操作系统提供的基本IO服务,与os绑定,特定于linix或unix平台。
- 标准IO标准I/O是ANSI C建立的一个标准I/O模型,是一个标准。
- 任何兼容POSIX标准的操作系统上都支持文件I/O。标准I/O被称为高级磁盘I/O,遵循ANSI C相关标准。只要开发环境中有标准I/O库,标准I/O就可以使用。我们现在学习的Linux系统中就包含了标准C库(使用的是GLIBC)
- 再来说说优劣:通过文件I/O读写文件时,每次操作都会执行相关系统调用。这样处理的好处是直接读写实际文件,坏处是频繁的系统调用会增加系统开销,标准I/O可以看成是在文件I/O的基础上封装了缓冲机制。先读写缓冲区,必要时再访问实际文件,从而减少了系统调用的次数。
- 问题2:命令行传参
举例:对于我们见到的main函数中的argc
和argv[]
argc == 1
就是说命令行参数的个数为0.argc
是参数个数,定义为int
argv
是字符串数组,存的是参数,定义为char**
或者char* argv[]
- 实例:比如你编译好的程序为
my.exe
,在命令行执行my.exe 1 2 3
,那argc
就是4,argv[0]
是"my.exe",argv[1]是"1",argv[2]是"2",argv[3]是"3"
;
代码调试中的问题和解决过程
-
问题1:
conflicting types for 'run'
-
解决:通过上网查阅这个错误
conflicting types
,在stackoverflow中找到了启发,了解到这是我修改函数的传入值之后忘记修改之前的函数声明导致的。 -
问题2:
use of undeclared identifier 'file'
-
解决:我查看了代码,发现之前使用文件IO的一个参数忘记注释掉了。
本周结对学习情况
- 结对学习博客
20155302 - 结对学习图片
- 结对学习内容
- 教材第十章
代码托管
学习进度条
代码行数(新增/累积) | 博客量(新增/累积) | 学习时间(新增/累积) | 重要成长 | |
---|---|---|---|---|
目标 | 5000行 | 30篇 | 400小时 | |
第一周 | 0/0 | 1/1 | 10/10 | |
第二周 | 0/0 | 0/1 | 10/20 | |
第三周 | 200/200 | 2/3 | 10/30 | |
第四周 | 100/300 | 1/4 | 10/40 |
- 计划学习时间:10小时
- 实际学习时间:10小时