2018-2019-1 20165325 《資訊安全系統設計基礎》第八週學習總結
2018-2019-1 20165325 《資訊安全系統設計基礎》第八週學習總結
一、學習筆記——網路程式設計
1、三種併發方式
構造併發程式的方法有三種:
- 程序
- 執行緒
- I/O多路複用
程序:用核心來呼叫和維護,有獨立的虛擬地址空間,顯式的程序間通訊機制。
執行緒:執行在一個單一程序上下文中的邏輯流。由核心進行排程,共享同一個虛擬地址空間。
I/O多路複用:應用程式在一個程序的上下文中顯式地排程控制流。邏輯流被模型化為狀態機。
2、C/S程式設計模型
客戶端和伺服器都是程序,C/S程式設計模型由一個伺服器程序和一個或多個客戶端程序組成
伺服器程序管理某種資源,通過操作這種資源來為它的客戶端提供某種服務。基本操作為事務,一個客戶端-伺服器事務由四步組成:
客戶端向伺服器傳送請求,發起一個事務;
伺服器收到請求,操作資源;
伺服器給客戶端傳送一個響應,並等待下一個請求。
客戶端收到響應並處理它。
3、執行緒控制及相關係統呼叫
在上一次的socket程式設計中,伺服器持續listen,如果有客戶端程序請求,伺服器父程序就會派生一個子程序來處理新的連線請求。這便存在基於程序的併發程式設計。
執行緒:執行子程序上下文中的邏輯流
執行緒與程序的不同:
執行緒的上下文切換要比程序的上下文切換快得多;
和一個程序相關的執行緒組成對等,獨立於其他執行緒建立的執行緒。
主執行緒和其他執行緒的區別僅在於它總是程序中第一個執行的執行緒。
建立執行緒
pthread create
:建立一個新的執行緒,在新執行緒的上下文中執行執行緒例程f。
新執行緒可以通過pthread _self
獲得自己的執行緒ID。
終止執行緒
一個執行緒的終止方式:
當頂層的執行緒例程返回,執行緒會隱式地終止;
pthread_exit
:執行緒顯式地終止。
注:如果主執行緒呼叫pthread _exit
,它會等待所有其他對等執行緒終止,然後再終止主執行緒和整個程序。
回收已終止執行緒的資源
pthread _join
:阻塞,直到執行緒tid終止,回收已終止執行緒佔用的所有儲存器資源。
注:pthread _join
只能等待一個指定的執行緒終止。
分離執行緒
在任何一個時間點上,執行緒是可結合的或者是分離的。一個可結合的執行緒能夠被其他執行緒收回其資源和殺死;一個可分離的執行緒是不能被其他執行緒回收或殺死的。它的儲存器資源在它終止時有系統自動釋放。
預設情況下,執行緒被建立成可結合的,為了避免儲存器漏洞,每個可集合的執行緒都應該要麼被其他程序顯式的回收,要麼通過呼叫
pthread _detach
被分離。
初始化執行緒
pthread _once
允許初始化與執行緒例程相關的狀態。once _control
變數是一個全域性或者靜態變數,總是被初始化為PTHREAD _ONCE _INIT
。
二、Linux實現命令——mypwd
1、pwd命令學習
在Linux中使用man命令檢視pwd:
實際操作使用pwd命令:
pwd命令的作用是檢視當前所在的工作路徑。
2、思路
基本原理:
每個目錄下都至少有兩個內容‘.’和’..’,其中‘.’代表當前目錄,’..’代表父目錄。每個目錄或檔案都有對應的i-節點號。
$ ls -1ia
(數字1,不是字母l):檢視當前目錄下的檔名和對應的i-節點號。
虛擬碼不會寫(寫出來不規範,可能只有自己看得懂),思路大概是:
檢視本目錄的i-節點,找到父目錄;
進入父目錄,輸出其i-節點對應的資料夾名;
迴圈以上過程直到到達根目錄;
注:首先找到的目錄是較小的子目錄,最後才讀取到根目錄。但是輸出是從根目錄開始的。
典型的輸入輸出逆序問題,一般兩種解決方案:一是用棧,二是用遞迴。
這裡我使用遞迴實現。
判斷是否抵達根目錄
根目錄的‘.’和’..’相同,i-節點號相同。
用到的核心函式
stat(char* fname, struct stat* bufp);
把檔案fname的資訊複製到bufp所指結構體裡(stat結構體包含了檔案的資訊,在/user/include/sys/stat.h中可以看到struct stat的成員變數。);readdir(DIR* dir_ptr)
讀取dir_ptr目錄的所有檔案和目錄,返回值是struct dirent結構體;每次呼叫都會指向下一個檔案,遍歷完後返回值為NULL;chdir
3、實現mypwd
程式碼:
///////////////////////////////////////////
//mypwd.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
void mypwd(ino_t this_inode);
void inum_to_name(ino_t inode_to_find,char* namebuf,int buflen);
ino_t get_inode(char* fname);
//返回檔案的i節點
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;
}
void mypwd(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(".");
mypwd(my_inode);
printf("/%s",its_name);
}
}
//找到i節點對應的檔名,並放在字元數組裡
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);
}
//尋找指定i節點的目錄,將目錄名複製到namebuf中。
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 while looking for inum %d : NOT FOUND!\n",(int)inode_to_find);
exit (1);
}
int main()
{
//顯示路徑
mypwd(get_inode("."));
putchar('\n');
return 0;
}