信息安全系統設計基礎第九周學習總結

信息安全系統設計基礎第九周學習總結

估算學習時間:共9小時
讀書:5
代碼:1
做業:1
博客:2
實際學習時間:共10.7小時
讀書:4.2
代碼:1.5
做業:2
博客:3
耗時估計的公式:Y=X+X/N ,Y=X-X/Nhtml

第十章 系統級I/O

  • 輸入輸出I/O是在主存和外部設備(如磁盤,網絡和終端)之間拷貝數據的過程。
  • 輸入就是從I/O設備拷貝數據到主存,而輸出就是從主存拷貝數據到I/O設備。
  • 全部語言的運行時系統都提供執行I/O的較高級別的工具。例如,ANSI C提供標準I/O庫,包含像printf和scanf這樣執行帶緩衝區的I/O函數。C++語言用它的重載操做符<<(輸出)和>>(輸入)提供了相似的功能。在UNIX系統中,是經過使用由內核提供的系統級Unix I/O函數來實現這些比較高級的I/O函數的。
  • 學習Unix I/O緣由:瞭解Unix I/O將幫助你理解其餘的系統概念;有時你除了使用Unix I/O外別無選擇。

10.1 unix i/o 596

全部的I/O設備,如網絡、磁盤和終端,都被模型化爲文件,而全部的輸入和輸出都被當作對相應的文件的讀和寫來執行。這種將設備優雅地映射爲文件的方式,容許Unix內核引出一個簡單、低級的的應用接口,稱爲Unⅸ I/O,這使得全部的輸入和輸出都能以一種統一且一致的方式來執行:node

  • 打開文件。一個應用程序經過要求內核打開相應的文件,來宣告它想要訪問一個I/O設備。內核返回一個小的非負整數,叫作描述符,它在後續對此文件的全部操做中標識這個文件。內核記錄有關這個打開文件的全部信息。應用程序只需記住這個描述符。Unⅸ外殼建立的每一個進程開始時都有三個打開的文件:標準輸入(描述符爲0)、標準輸出(描述符爲1)和標準錯誤(描述符爲2)。頭文件可用來代替顯式的描述符值。
  • 改變當前的文件位置。對於每一個打開的文件,內核保持着一個文件位置k,初始爲0。這個文件位置是從文件開頭起始的字節偏移量。應用程序可以經過執行seek操做,顯式地設置文件的當前位置爲k。
  • 讀寫文件。一個讀操做就是從文件拷貝n>0個字節到存儲器,從當前文件位置k開始,而後將k增長到k+n。給定一個大小爲m字節的文件,當k>=m時執行讀操做會觸發―個稱爲end-of-file(EOF)的條件,應用程序能檢測到這個條件。在文件結尾到處並無明確的「EOF」符號。
  • 關閉文件。當應用完成了對文件的訪問以後,它就通知內核關閉這個文件。做爲響應,內核釋放文件打開時建立的數據結構,並將這個描述符恢復到可用的描述符池中。不管一個進程由於何種緣由終止時,內核都會關閉全部打開的文件並釋放它們的存儲器資源。

10.2 打開和關閉文件 597

  • 進程是經過調用open函數來打開一個已存在的文件或者建立一個新文件:
    ios

  • flags參數表示進程打算如何訪問這個文件,它的值包括:程序員

O_RDONLY
O_WRONLY
O_RDWR安全

  • flags參數也能夠是一個或者更多位掩碼的或,提供一些額外的指示:

O_CREAT
O_TRUNC:若是文件已經存在,就截斷它。
O_APPEND網絡

  • mode參數指定了新文件的訪問權限位。符號名字以下圖。做爲上下文的一部分,每一個進程都有一個umask它是經過調用umask函數來設置的。當進程經過帶某個mode參數的open函數調用來建立一個新文件時,文件的訪問權限位被設置爲mode&umask。

10.3 讀和寫文件 598

應用程序是經過分別調用系統函數 read和write函數來執行輸入和輸出的。
數據結構

旁註:size_t是做爲usigned int,而ssize_t是做爲int。socket

在某些狀況下,read和write傳送的字節比應用程序要求的要少。出現這種狀況的可能的緣由有:函數

讀時遇到EOF。假設該文件從當前文件位置開始只含有20個字節,而應用程序要求咱們以50個字節的片進行讀取,這樣一來,這個read的返回的值是20,在此以後的read則返回0。
從終端讀文本行。若是打開的文件是與終端相關聯的,那麼每一個read函數將一次傳送一個文本行,返回的不足值等於文本行的大小。
讀和寫socket。若是打開的文件對應於網絡套接字,那麼內部緩衝約束和較長的網絡延遲會致使read和write返回不足值。工具

10.4 用rio包健壯地讀寫 599

RIO提供了兩類不一樣的函數:

無緩衝的輸入輸出函數
帶緩衝的輸入函數

10.4.1 rio的無緩衝的輸入輸出函數 600

  • rio_readn函數從描述符fd的當前文件位置最多傳送n個字節到存儲器位置usrbuf。相似的rio_writen函數從位置usrbuf傳送n個字節到描述符fd。rio_readn函數在遇到EOF時只能返回一個不足值。rio_writen函數毫不會返回不足值。
  • 注意:若是rio_readn和rio_writen函數被一個從應用信號處理程序的返回中斷,那麼每一個函數都會手動地重啓read或write。

10.4.2 rio的帶緩衝的輸入函數 600

  • 一個文本行就是一個由 換行符 結尾的ASCII碼字符序列。在Unix系統中,換行符是‘\n’,與ASCII碼換行符LF相同,數值爲0x0a。假設咱們要編寫一個程序來計算文本文件中文本行的數量應該如何來實現呢?

一種方法是用read函數來一次一個字節地從文件傳送到用戶存儲器,檢查每一個字節來查找換行符。這種方法的問題就是效率不高,每次取文件中的一個字節都要求陷入內核。
一種更好的方法是調用一個包裝函數(rio_readlineb),它從一個內部緩衝區拷貝一個文本行,當緩衝區變空時,會自動的調用read系統調用來從新填滿緩衝區。

  • 在帶緩衝區的版本中,每打開一個描述符都會調用一次rio_readinitb函數,它將描述符fd和地址rp處的一個類型爲rio_t的讀緩衝區聯繫起來。
  • rio_readinitb函數從文件rp讀取一個文本行(包括結尾的換行符),將它拷貝到存儲器位置usrbuf,而且用空字符來結束這個文本行。
  • RIO讀程序的核心是rio_read函數,rio_read函數能夠當作是Unix read函數的帶緩衝區的版本。當調用rio_read要求讀取n個字節的時候,讀緩衝區內有rp->rio_cnt個未讀的字節。若是緩衝區爲空的時候,就會調用read系統函數去填滿緩衝區。這個read調用收到一個不足值的話並非一個錯誤,只不過讀緩衝區的是填充了一部分。
  • 一旦緩衝區非空,rio_read就從讀緩衝區拷貝n和rp->rio_cnt中較小值個字節到用戶緩衝區,並返回拷貝字節的數目。
  • 對於應用程序來講,rio_read和系統調用read有着相同的語義。出錯時返回-1;在EOF時,返回0;若是要求的字節超過了讀緩衝區內未讀的字節的數目,它會返回一個不足值。rio_readlineb函數屢次調用rio_read函數。每次調用都從讀緩衝區返回一個字節,而後檢查這個字節是不是結尾的換行符。
  • rio_readlineb函數最多讀取(maxlen-1)個字節,餘下的一個字節留給結尾的空字符。超過maxlen-1字節的文本行被截斷,並用一個空字符結束。

10.5 讀取文件元數據 604

  • 應用程序可以經過調用stat和fstat函數,檢索到關於文件的信息。

  • stat函數結構

  • st_size成員包含了文件的字節數大小。st_mode成員則編碼了文件訪問許可位和文件類型。Unix識別大量不一樣的文件類型。普通文件包括某種類型的二進制或文本數據。對於內核而言,文本文件和二進制文件毫無區別。

  • 目錄文件包含關於其餘文件的信息。套接字是一種用來經過網絡與其餘進程通訊的文件。Unix提供的宏指令根據st_mode成員來肯定文件的類型。這些宏的一個子集以下:

10.6 共享文件 606

內核用三個相關數據結構來表示打開的文件

描述符表
文件表
v-node表

10.7 i/o重定向 608

  • Unix外殼提供了I/O重定向操做符,容許用戶將磁盤文件和標準輸入輸出聯繫起來。

  • I/O重定向的工做方式: 一種是使用dup2函數。

  • dup2函數拷貝描述符表表項oldfd到描述符表表項newfd,覆蓋描述符表表項newfd之前的內容。若是newfd已經打開了,dup2會在拷貝oldfd以前關閉newfd。

10.8 標準i/o 609

  • ANSI C定義了一組高級輸入輸出函數,成爲標準I/O庫,爲程序員提供了Unix I/O的較高級別的替代。這個庫(libc)提供了打開和關閉文件的函數(fopen和fclose)、讀和寫字節的函數(fread和fwrite)、讀和寫字符串的函數(fgets和fputs)、以及複雜的格式化I/O函數(printf和scanf)。

  • 標準I/O庫將一個打開的文件模型化爲一個流。對於程序員而言,一個流就是一個指向FILE類型的結構的指針。每一個ANSI C程序開始時都有三個打開的流stdin、stdout和stderr,分別對應於標準輸入、標準輸出和標準錯誤:

10.9 綜合:我該使用哪些i/o函數 610

  • 這一章討論過的各類I/O包

  • 標準I/O流,從某種意義上來講是全雙工的,由於程序可以在同一個流上執行輸入和輸出。

  • 建議在網絡套接字上不要使用標準I/O函數來進行輸入和輸出。而要使用健壯的RIO函數。

10.10 小結 611

  • Unix提供了少許的系統級函數,它們容許應用程序打開、關閉、讀和寫文件,提取文件的元數據,以及執行I/O重定向。Unix的讀和寫操做會出現不足值,應用程序必須能正確地預計和處理這種狀況。應用程序不該直接調用unⅸ I/O函數,而應該使用RIO包,RIO包經過反覆執行讀寫操做,直到傳送完全部的請求數據,自動處理不足值。
  • Unix內核使用三個相關的數據結構來表示打開的文件。描述符表中的表項指向打開文件中的表項,而打開文件表中的表項又指向v-node表中的表項,每一個進程都有它本身單獨的描述符表,而全部的進程共享同一個打開文件表和v-node表,理解這些結構的通常組成就能使咱們清楚地理解文件共享和I/O重定向。
  • 標準I/O庫是基於Unix I/O實現的,並提供了一組強大的高級I/O例程,對於大多數應用程序而言,標準I/O更簡單,是優於Unix I/O的選擇。然而,由於對標準I/O和網絡文件的一些相互不兼容的限制,Unix I/O比標準I/O更適用於網絡應用程序。

重點

  1. 閱讀教材,注意每一個系統調用的參數、返回值,會查幫助文檔
    完成課後練習(書中有參考答案)重點:10.一、10.二、10.三、10.四、10.5
  2. 重要命令:
    man -k key1 | grep key2| grep 2 : 根據關鍵字檢索系統調用
    grep -nr XXX /usr/include :查找宏定義,類型定義

實踐代碼

cp1

#include        <stdio.h>
#include        <stdlib.h>
#include        <unistd.h>
#include        <fcntl.h>

define BUFFERSIZE      4096
#define COPYMODE        0644

void oops(char *, char *);

int main(int argc, char *argv[])
{
int in_fd, out_fd, n_chars;
char buf[BUFFERSIZE];
if (argc != 3) {
	fprintf(stderr, "usage: %s source destination\n", *argv);
	exit(1);
}

if ((in_fd = open(argv[1], O_RDONLY)) == -1)
	oops("Cannot open ", argv[1]);

if ((out_fd = creat(argv[2], COPYMODE)) == -1)
	oops("Cannot creat", argv[2]);

while ((n_chars = read(in_fd, buf, BUFFERSIZE)) > 0)
	if (write(out_fd, buf, n_chars) != n_chars)
		oops("Write error to ", argv[2]);
if (n_chars == -1)
	oops("Read error from ", argv[1]);


if (close(in_fd) == -1 || close(out_fd) == -1)
	oops("Error closing files", "");
}

void oops(char *s1, char *s2)
{
fprintf(stderr, "Error: %s ", s1);
perror(s2);
exit(1);
}

echostate

#include<stdio.h>
#include<stdlib.h>
#include<termios.h>

int main()
{
struct termios info;
int rv;

rv = tcgetattr( 0, &info ); /* read values from driver  */

if ( rv == -1 ){
perror( "tcgetattr");
exit(1);
}
if ( info.c_lflag & ECHO )
printf(" echo is on , since its bit is 1\n");
else
printf(" echo is OFF, since its bit is 0\n");

		return 0;
}

ls1

#include	<stdio.h>
#include	<sys/types.h>
#include	<dirent.h>

void do_ls(char []);

int main(int argc, char *argv[])
{
	if ( argc == 1 )
		do_ls( "." );
	else
		while ( --argc ){
			printf("%s:\n", *++argv );
			do_ls( *argv );
		}

	return 0;
}

void do_ls( char dirname[] )
{
	DIR		*dir_ptr;		
	struct dirent	*direntp;		

	if ( ( dir_ptr = opendir( dirname ) ) == NULL )
		fprintf(stderr,"ls1: cannot open %s\n", dirname);
	else
	{
		while ( ( direntp = readdir( dir_ptr ) ) != NULL )
			printf("%s\n", direntp->d_name );
		closedir(dir_ptr);
	}
}

ls2

#include	<stdio.h>
#include<string.h>
#include	<sys/types.h>
#include	<dirent.h>
#include	<sys/stat.h>

void do_ls(char[]);
void dostat(char *);
void show_file_info( char *, struct stat *);
void mode_to_letters( int , char [] );
char *uid_to_name( uid_t );
char *gid_to_name( gid_t );

int main(int argc, char *argv[])
{
	if ( argc == 1 )
		do_ls( "." );
	else
		while ( --argc ){
			printf("%s:\n", *++argv );
			do_ls( *argv );
		}

	return 0;
}

void do_ls( char dirname[] )
{
	DIR		*dir_ptr;		
	struct dirent	*direntp;		

	if ( ( dir_ptr = opendir( dirname ) ) == NULL )
		fprintf(stderr,"ls1: cannot open %s\n", dirname);
	else
	{
		while ( ( direntp = readdir( dir_ptr ) ) != NULL )
			dostat( direntp->d_name );
		closedir(dir_ptr);
	}
}

void dostat( char *filename )
{
	struct stat info;

	if ( stat(filename, &info) == -1 )		
		perror( filename );			
	else					
		show_file_info( filename, &info );
}

void show_file_info( char *filename, struct stat *info_p )
{
	char	*uid_to_name(), *ctime(), *gid_to_name(), *filemode();
	void	mode_to_letters();
charmodestr[11];

	mode_to_letters( info_p->st_mode, modestr );

	printf( "%s", modestr );
	printf( "%4d "  , (int) info_p->st_nlink);	
	printf( "%-8s " , uid_to_name(info_p->st_uid) );
	printf( "%-8s " , gid_to_name(info_p->st_gid) );
	printf( "%8ld " , (long)info_p->st_size);
	printf( "%.12s ", 4+ctime(&info_p->st_mtime));
	printf( "%s\n"  , filename );

}

void mode_to_letters( int mode, char str[] )
{
strcpy( str, "----------" );   

if ( S_ISDIR(mode) )  str[0] = 'd';
if ( S_ISCHR(mode) )  str[0] = 'c';
if ( S_ISBLK(mode) )  str[0] = 'b';

if ( mode & S_IRUSR ) str[1] = 'r';
if ( mode & S_IWUSR ) str[2] = 'w';
if ( mode & S_IXUSR ) str[3] = 'x';

if ( mode & S_IRGRP ) str[4] = 'r';
if ( mode & S_IWGRP ) str[5] = 'w';
if ( mode & S_IXGRP ) str[6] = 'x';

if ( mode & S_IROTH ) str[7] = 'r';
if ( mode & S_IWOTH ) str[8] = 'w';
if ( mode & S_IXOTH ) str[9] = 'x';
}

#include	<pwd.h>

char *uid_to_name( uid_t uid )
{
	struct	passwd *getpwuid(), *pw_ptr;
	static  char numstr[10];

	if ( ( pw_ptr = getpwuid( uid ) ) == NULL ){
		sprintf(numstr,"%d", uid);
		return numstr;
	}
	else
		return pw_ptr->pw_name ;
}

#include	<grp.h>

char *gid_to_name( gid_t gid )
{
	struct group *getgrgid(), *grp_ptr;
	static  char numstr[10];

	if ( ( grp_ptr = getgrgid(gid) ) == NULL ){
		sprintf(numstr,"%d", gid);
		return numstr;
	}
	else
		return grp_ptr->gr_name;
}

fileinfo

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

void show_stat_info(char *, struct stat *);

int main(int argc, char *argv[])
{
struct stat info;

if (argc>1)
	{
	
if( stat(argv[1], &info) != -1 ){
show_stat_info( argv[1], &info );
return 0;
}
else
perror(argv[1]);  
	}
return 1;
}
void show_stat_info(char *fname, struct stat *buf)
{
printf("   mode: %o\n", buf->st_mode); 
printf("  links: %d\n", buf->st_nlink);
printf("   user: %d\n", buf->st_uid);  
printf("  group: %d\n", buf->st_gid);  
printf("   size: %d\n", (int)buf->st_size); 
printf("modtime: %d\n", (int)buf->st_mtime);
printf("   name: %s\n", fname );   
}

filesize

#include <stdio.h>
#include <sys/stat.h>

int main()
{
	struct stat infobuf;   

	if ( stat( "/etc/passwd", &infobuf) == -1 )
		perror("/etc/passwd");
	else
		printf(" The size of /etc/passwd is %d\n", infobuf.st_size );
}

setecho

#include<stdio.h>
#include 		<stdlib.h>
#include<termios.h>

#define  oops(s,x) { perror(s); exit(x); }

int main(int argc, char *argv[])
{
struct termios info;

if ( argc == 1 ) 
		exit(0);

if ( tcgetattr(0,&info) == -1 )  /* get attribs   */
			oops("tcgettattr", 1);

if ( argv[1][0] == 'y' )
info.c_lflag |= ECHO ;  /* turn on bit*/
else
info.c_lflag &= ~ECHO ; /* turn off bit   */

if ( tcsetattr(0,TCSANOW,&info) == -1 ) /* set attribs*/
   oops("tcsetattr",2);
	
		return 0;
}

spwd

#include	<stdio.h>
#include<stdlib.h>
#include<string.h>
#include	<sys/types.h>
#include	<sys/stat.h>
#include	<dirent.h>

ino_t	get_inode(char *);
voidprintpathto(ino_t);
voidinum_to_name(ino_t , char *, int );

int main()
{
	printpathto( get_inode( "." ) );	
	putchar('\n');				
	return 0;
}

void printpathto( ino_t this_inode )
{
	ino_t	my_inode ;
	char	its_name[BUFSIZ];

	if ( get_inode("..") != this_inode )
	{
		chdir( ".." );				

		inum_to_name(this_inode,its_name,BUFSIZ);

		my_inode = get_inode( "." );		
		printpathto( my_inode );		
		printf("/%s", its_name );		
							
	}
}

void inum_to_name(ino_t inode_to_find , char *namebuf, int buflen)
{
	DIR		*dir_ptr;		
	struct dirent	*direntp;		

	dir_ptr = opendir( "." );
	if ( dir_ptr == NULL ){
		perror( "." );
		exit(1);
	}


	while ( ( direntp = readdir( dir_ptr ) ) != NULL )
		if ( direntp->d_ino == inode_to_find )
		{
			strncpy( namebuf, direntp->d_name, buflen);
			namebuf[buflen-1] = '\0';   
			closedir( dir_ptr );
			return;
		}
	fprintf(stderr, "error looking for inum %d\n", (int) inode_to_find);
	exit(1);
}

ino_t get_inode( char *fname )
{
	struct stat info;

	if ( stat( fname , &info ) == -1 ){
		fprintf(stderr, "Cannot stat ");
		perror(fname);
		exit(1);
	}
	return info.st_ino;
}

testioctl

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>

int main()
{
	struct winsize size;
	if( isatty(STDOUT_FILENO) == 0)
		exit(1);
	if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &size) < 0) {
		perror("ioctl TIOCGWINSZ error");
		exit(1);
	}

	printf("%d rows %d columns\n", size.ws_row, size.ws_col);
	return 0;
}

who1

#include	<stdio.h>
#include<stdlib.h>
#include	<utmp.h>
#include	<fcntl.h>
#include	<unistd.h>

#define	SHOWHOST	

int show_info( struct utmp *utbufp )
{
	printf("%-8.8s", utbufp->ut_name);	
	printf(" ");				
	printf("%-8.8s", utbufp->ut_line);	
	printf(" ");				
	printf("%10ld", utbufp->ut_time);	
	printf(" ");				
#ifdef	SHOWHOST
	printf("(%s)", utbufp->ut_host);	
#endif
	printf("\n");				

	return 0;
}
int main()
{
	struct utmp	 current_record;	
	int		utmpfd;		
	int		reclen = sizeof(current_record);

	if ( (utmpfd = open(UTMP_FILE, O_RDONLY)) == -1 ){
		perror( UTMP_FILE );	
		exit(1);
	}
	while ( read(utmpfd, &current_record, reclen) == reclen )
		show_info(&current_record);
	close(utmpfd);
	return 0;			
}

who2

#include	<stdio.h>
#include<stdlib.h>
#include	<utmp.h>
#include	<fcntl.h>
#include	<unistd.h>

#define	SHOWHOST	

int show_info( struct utmp *utbufp )
{
	printf("%-8.8s", utbufp->ut_name);	
	printf(" ");				
	printf("%-8.8s", utbufp->ut_line);	
	printf(" ");				
	printf("%10ld", utbufp->ut_time);	
	printf(" ");				
#ifdef	SHOWHOST
	printf("(%s)", utbufp->ut_host);	
#endif
	printf("\n");				

	return 0;
}
int main()
{
	struct utmp	 current_record;	
	int		utmpfd;		
	int		reclen = sizeof(current_record);

	if ( (utmpfd = open(UTMP_FILE, O_RDONLY)) == -1 ){
		perror( UTMP_FILE );	
		exit(1);
	}
	while ( read(utmpfd, &current_record, reclen) == reclen )
		show_info(&current_record);
	close(utmpfd);
	return 0;			
}

遇到的問題

  1. 沒法運行第十章代碼怎麼辦?
    解決方法:增長頭文件庫。
    參考資料:http://group.cnblogs.com/topic/73278.html
  2. 虛擬機打開速度很是緩慢,已經打不開了?
    增大內存

參考資料

  1. 教材:第十章,詳細學習指導:http://group.cnblogs.com/topic/73069.html
  2. 課程資料:https://www.shiyanlou.com/courses/413 實驗十,課程邀請碼:W7FQKW4Y
  3. 教材中代碼運行、思考一下,讀代碼的學習方法:http://www.cnblogs.com/rocedu/p/4837092.html。
  4. CSAPP第10章系統級I/O問題:http://www.zhihu.com/question/31499851
相關文章
相關標籤/搜索