2017-2018-1 20155208 《信息安全系統設計基礎》第四周學習總結
2017-2018-1 20155208 《信息安全系統設計基礎》第四周學習總結
學習任務
- 參考教材第十章內容
- 用Linux IO相關系統調用編寫myod.c 用myod XXX實現Linux下od -tx -tc XXX的功能,註意XXX是文件名,通過命令行傳入,不要讓用戶輸入文件名
- 不要把代碼都寫入main函數中
- 要分模塊,不要把代碼都寫入一個.c中
- 提交測試代碼和運行結果截圖, 提交調試過程截圖,要全屏,包含自己的學號信息
- 課上上傳代碼到碼雲
Linux下od命令的學習
1、 od命令解釋:
用於輸出文件的八進制、十六進制或其它格式碼的字節,通常用於顯示或查看文件中,不能直接顯示在終端的字符。 常見的文件為文本文件和二進制文件。此命令主要用來查看保存在二進制文件中的值。比如,程序可能輸出大量的數據記錄,每個數據是一個單精度浮點數。這些數據記錄存放在一個文件中,如果想查看下這個數據,這時候od命令就派上用場了。在我看來,od命令主要用來格式化輸出文件數據,即對文件中的數據進行無二義性的解釋。不管是IEEE754格式的浮點數還是ASCII碼,od命令都能按照需求輸出它們的值。
2、參數
命令 | 作用 |
---|---|
-a | 此參數的效果和同時指定"-ta"參數相同。 |
-A<字碼基數> | 選擇要以何種基數計算字碼。 |
-b | 此參數的效果和同時指定"-toC"參數相同。 |
-c | 此參數的效果和同時指定"-tC"參數相同。 |
-d | 此參數的效果和同時指定"-tu2"參數相同。 |
-f | 此參數的效果和同時指定"-tfF"參數相同。 |
-h | 此參數的效果和同時指定"-tx2"參數相同。 |
-i | 此參數的效果和同時指定"-td2"參數相同。 |
-j<字符數目>或--skip-bytes=<字符數目> | 略過設置的字符數目。 |
-l | 此參數的效果和同時指定"-td4"參數相同。 |
-N<字符數目>或--read-bytes=<字符數目> | 到設置的字符數目為止。 |
-o | 此參數的效果和同時指定"-to2"參數相同。 |
-s<字符串字符數>或--strings=<字符串字符數> | 只顯示符合指定的字符數目的字符串。 |
-t<輸出格式>或--format=<輸出格式> | 設置輸出格式。 |
-v或--output-duplicates | 輸出時不省略重復的數據。 |
-w<每列字符數>或--width=<每列字符數> | 設置每列的最大字符數。 |
-x | 此參數的效果和同時指定"-h"參數相同。 |
--help | 在線幫助。 |
--version | 顯示版本信息 |
實例效果:
執行下列命令:
echo abcdef g > tmp
cat tmp
od -b tmp
運行結果如圖:
3、 用Linux IO相關系統調用編寫myod.c 用myod 實現Linux下od -tx -tc :
運行代碼為:
#include <stdio.h>
#include <stdlib.h>
#include"head.h"
int main(int argc,char *argv[])
{
int i;
int n1=0,n2=0,n3=0,n4=0;
for(i=1;i<argc-1;i++)
{
switch(argv[i][2])
{
case ‘c‘:n1=1;break;
case ‘x‘:n2=1;break;
case ‘d‘:n3=1;break;
case ‘o‘:n4=1;break;
}
}
FILE *file=fopen(argv[argc-1],"r");
if(file==NULL){printf("Error!\n");exit(0);}
myod(file,n1,n2,n3,n4);
return 0;
}
#include<stdio.h>
void myod(FILE *file,int n1,int n2,int n3,int n4)
{
char ch,line[16];
int i;
int j=0;
while((ch=fgetc(file))!=EOF){
line[j%16]=ch;
if((j+1)%16==0){
if(n1){for(i=0;i<16;i++)
{
if(line[i]==‘\n‘)
{printf("%5s","\\n");continue;}
if(line[i]==‘\t‘)
{printf("%5s","\\t");continue;}
putchar(line[i]);
putchar(‘ ‘);
putchar(‘ ‘);
putchar(‘ ‘);
putchar(‘ ‘);
}
putchar(‘\n‘);}
if(n2){for(i=0;i<16;i++)
{
if(line[i]==‘\n‘)
{printf("0%-4x",‘\n‘);continue;}
if(line[i]==‘\t‘)
{printf("0%-4x",‘\t‘);continue;}
printf("%-5x",line[i]);
}
putchar(‘\n‘);
}
if(n3){for(i=0;i<16;i++)
{
if(line[i]==‘\n‘)
{printf("%-5d",‘\n‘);continue;}
if(line[i]==‘\t‘)
{printf("%-5d",‘\t‘);continue;}
printf("%-5d",line[i]);
}
putchar(‘\n‘);
}
if(n4){for(i=0;i<16;i++)
{
if(line[i]==‘\n‘)
{printf("%-5o",‘\n‘);continue;}
if(line[i]==‘\t‘)
{printf("%-5o",‘\t‘);continue;}
printf("%-5o",line[i]);
}
putchar(‘\n‘);
}
printf("下一行!\n");
}
j++;
}
}
代碼編寫中遇到的問題
問題: 關於char *argv的使用。
解決: 通過查找資料得知 argc是命令行總的參數個數 argv[]是argc個參數,其中第0個參數是程序的全名,以後的參數 命令行後面跟的用戶輸入的參數;
char *argv[]是一個字符數組,其大小是int argc,主要用於命令行參數 argv[] 參數,數組裏每個元素代表一個參數;argc記錄了用戶在運行程序的命令行中輸入的參數的個數 ;arg[]指向的數組中至少有一個字符指針,即arg[0].他通常指向程序中的可執行文件的文件名。在有些版本的編譯器中還包括程序 文件所在的路徑;
教材學習內容總結
第十章學習
- 輸入/輸出(I/O)是在主存和外部設備(如磁盤驅動器、終端和網絡)之間拷貝數據的過程。輸入操作是從I/O設備拷貝數據到主存,而輸出操作是從主存拷貝數據到I/O設備。
10.1 Unix I/O:
-
打開文件 1、應用程序向內核發出請求
2、要求內核打開相應的文件
3、內核返回文件描述符
-
一個小的非負整數,用來在後續對此文件的所有操作中標識這個文件叫做文件描述符,有三個已經指定了的文件描述符為:
標準輸入——0(STDIN_FILENO)
標準輸出——1(STDOUT_FILENO)
標準錯誤——2(STDERR_FILENO)
-
也就是說,在Unix生命周期一開始,0、1、2就被占用,以後的open只能從3開始,並且在UNIX下還有stdin,stdout,stderr表示同樣的含義。
10.2打開和關閉文件
-
打開文件:int open(char *filename, int flags, mode_t mode)
-
flags參數指明了進程打算如何訪問這個文件:
O_RDONLY:只讀
O_WRONLY:只寫
O_RDWR:可讀可寫
-
flags參數也可以是一個或者更多位掩碼的或:
O_CREAT:如果文件不存在,就創建它的一個截斷的文件
O_TRUNC:如果文件已存在,就截斷它
O_APPEND:在每次寫操作前,設置文件的位置到文件的結尾處
-
關閉文件
int close(int fd)
10.3讀和寫文件
1、讀 read
函數原型:
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t n);
2、寫 write
函數原型:
#include <unistd.h>
ssize_t write(int fd, void *buf, size_t n);
10.4用RIO包健壯的讀寫
-
通過調用 rio_readn 和 rio_write函數,應用程序可以在內存和文件之間直接傳送數據。
-
rio_readn函數在遇到EOF時只能返回一個不足值;而rio_write函數絕不會返回不同值;
-
參數解析:
fd:文件描述符
usrbuf:存儲器位置
n:傳送的字節數
返回值:
rio_readn成功則返回傳送的字節數,EOF為0(一個不足值),出錯為-1。
rio_writen成功則返回傳送的字節數,出錯為-1,沒有不足值。
-
RIO的帶緩沖的輸入函數
缺點:效率不是很高,每讀取文件中的一個字節都要求陷入內核
10.5 讀取文件元數據
-
應用程序能夠通過調用stat和fstat函數,檢索到關於文件的信息:元數據
-
兩種輸入方式:
stat函數以一個文件名作為輸入
fstat函數以文件描述符作為輸入
-
stat數據結構中的st_size成員包含了文件的字節數大小,st_mode成員編碼了文件訪問許可位和文件類型。
10.6 共享文件
內核用三個相關的數據結構來表示打開的文件:
- 描述符表:每個進程都它獨立的描述符表,每個打來的描述符表指向文件表中的一個表項。
- 文件表:打開文件的集合是由一張文件表來表示的。
- v-node表:所有進程共享,每個表項包含stat結構中的大多數信息
10.7 I/O重定向
-
使用dup2函數:
int dup2(int oldfd,int newfd);
-
dup2函數拷貝描述符表表項oldfd到描述符表表項newfd
10.8 標準I/O
-
標準I/O庫將一個打開的文件模型化為一個流,一個流就是一個指向FILE類型的結構的指針
-
ANSI C程序開始時有三個打開的流:標準輸入stdin、標準輸出stdout和標準錯誤stderr
-
類型為FILE的流是對文件描述符和流緩沖區的抽象
附錄A 錯誤處理
錯誤處理風格
- Unix風格
遇到錯誤後返回-1,並且將全局變量errno設置為指明錯誤原因的錯誤代碼;
如果成功完成,就返回有用的結果。
- Posix風格
返回0表示成功,返回非0表示失敗;
有用的結果在傳進來的函數參數中。
- DNS風格
有兩個函數,gethostbyname和gethostbyaddr,失敗時返回NULL指針,並設置全局變量h_errno。
完成head,tail的使用,相關API的分析,偽代碼,產品代碼,測試代碼的編寫
- head命令用來查看文件的前幾行內容,默認是查看前10行的內容,也可以設置一個數字改變查看行數
head hello.c/*當前目錄下的文件名稱*/
head -20 hello.c
- tail命令用來查看文件的最後幾行內容,默認是查看最後10行的內容,同樣,也可以設置一個數字改變查看行數
tail -20 hello.c
運行代碼效果如圖:
代碼:
#ifndef HEAD_H
#define HEAD_H
void main(int argc,char *argv[]);
void ihead(char *ch[],int n);
#endif
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include"head.h"
#define N 1000
void main(int argc,char *argv[])
{
char ch[N];
int i,find,n;
if((find=open(argv[1],O_RDONLY))==-1)
{
perror(argv[1]);
exit(1);
}
n=read(find,ch,N);
ihead(ch,n);
close(find);
}
#include<stdio.h>
#include"head.h"
void ihead(char *ch[],int n)
{
int k,count=0;
for(k=0;k<n,count<10;i++)
{
if(ch[k]!=‘\n‘)
printf("%c",ch[k]);
else {
count++;
printf("\n");
}
}
}
代碼托管
碼雲鏈接
學習進度條
代碼行數(新增/積累) | 博客量(新增/積累 | 學習時間(新增/累積) | |
---|---|---|---|
目標 | 5000行 | 30篇 | 400小時 |
第一周 | 5/5 | 1/1 | 8/8 |
第二周 | 120/120 | 1/1 | 12/12 |
第三周 | 100/100 | 1/1 | 15/15 |
第四周 | 80/80 | 1/1 | 9/9 |
參考資料
《深入理解計算機系統V3》學習指導
詳細介紹Linux指令od
2017-2018-1 20155208 《信息安全系統設計基礎》第四周學習總結