20145321 《信息安全系統設計基礎》第13周學習總結
教材內容總結
第十一章 網絡編程
客戶端-服務器編程模型
- 一個服務器進程 -- 管理某種資源 -- 經過操做這種資源來爲它的客戶端提供某種服務
- 一個應用是由一個服務器進程和一個或者多個客戶端進程組成的
網絡
對主機而言:網絡是一種I/O設備git
- 從網絡上接收到的數據從適配器通過I/O和存儲器總線拷貝到存儲器,典型地是經過DMA(直接存儲器存取方式)傳送。
物理上而言,網絡是一個按照地理遠近組成的層次系統。程序員
- 最底層是LAN(局域網)
- 適配器提供到網絡的物理接口
以太網段(電纜+集線器)編程
- 包括一些電纜和集線器。每根電纜都有相同的最大位帶寬,集線器不加分辯地將一個端口上收到的每一個位複製到其餘全部的端口上,所以每臺主機都能看到每一個位。
- 一臺主機能夠發送一段位,稱爲幀。每一個主機適配器都能看到這個幀,可是隻有目的主機實際讀取它。
- 多個以太網段能夠鏈接成較大的局域網,稱爲橋接以太網。
- 網橋比集線器更充分的利用了電纜帶寬。
- 每一個以太網適配器都有一個全球惟一的48位地址,存儲在適配器的非易失性存儲器上。
網絡協議提供兩種基本能力瀏覽器
- 命名機制:惟一的標示一臺主機
- 傳送機制:定義一種把數據位捆紮成不連續的片的同一方式
全球IP因特網
TCP/IP其實是一個協議族安全
- IP機制從某種意義上而言是不可靠的。TCP是一個構建在IP之上的複雜協議,提供了進程間可靠地全雙工鏈接。
IP地址服務器
- 一個IP地址就是一個32位無符號整數
- IP/TCP爲任意整數數據項定義了統一的網絡字節順序(大端字節順序)
- 對inet-aton的調用傳遞的是指向結構的指針,而對inet_ntoa的調用傳遞的是結構自己
世界範圍的主機集合網絡
- 主機集合被映射爲一組32位的IP地址
- 這組IP地址被映射爲一組稱爲因特網域名的標識符
- 因特網主機上的進程可以經過鏈接和任何其餘主機上的進程
因特網鏈接多線程
- 點對點、全雙工、可靠
- 客戶端套接字地址中的端口是由內核自動分配的,稱爲臨時端口
- 服務端套接字地址中的端口一般是某個知名端口
套接字接口
函數併發
- socket函數:客戶端和服務端使用socket函數來建立一個套接字描述符
- connect函數:創建和服務器的鏈接。
- open_clientfd函數:將socket和connect函數包裝而成。客戶端能夠用它來和服務器創建鏈接。
- bind函數:將一本地地址與一套接口捆綁。
- listen函數:使用主動鏈接套接字變爲被鏈接套接口,使得一個進程能夠接受其它進程的請求,從而成爲一個服務器進程。
- open_listenfd函數:socket、bind和listen函數結合。用於服務器建立一個監聽描述符。
- accept函數:均被服務器用於和客戶端創建鏈接。
Web服務器
協議socket
- Web 客戶端和服務器之間的交互用的是一個基於文本的應用級協議,叫作 HTTP (Hypertext Transfer Protocol,超文本傳輸協議). HTTP 是一個簡單的協議。一個 Web 客戶端(即瀏覽器) 打開一個到服務器的因特網鏈接,而且請求某些內容。服務器響應所請求的內容,而後關閉鏈接。瀏覽器讀取這些內容,並把它顯示在屏幕上。
內容
- Web內容能夠用一種叫作 HTML(Hypertext Markup Language,超文本標記語言)的語言來編寫。一個 HTML 程序(頁)包含指令(標記),它們告訴瀏覽器如何顯示這頁中的各類文本和圖形對象。
- 對於Web客戶端和服務端而言,內容是與一個MIME類型相關的字節序列
- Web 服務器以兩種不一樣的方式向客戶端提供內容:
- 取一個磁盤文件,並將它的內容返回給客戶端。磁盤文件稱爲靜態內容 , 而返回文件給客戶端的過程稱爲服務靜態內容
- 運行一個可執行文件,並將它的輸出返回給客戶端。運行時可執行文件產生的輸出稱爲態內容 ,而運行程序並返回它的輸出到客戶端的過程稱爲服務動態內容
- 每條由Web服務器返回的內容都是和他管理的某個文件相關聯的。這些文件每個都有一個惟一的名字,叫作:URL
第十二章 併發編程
使用應用級併發的應用程序稱爲併發程序。現代操做系統提供了三種基本的構造併發程序的方法:
- 進程。每一個邏輯控制流都是一個進程,由內核來調度和維護。由於進程 有獨立的虛擬地址空間,想要和其餘流通訊,控制流必須使用某種顯式的進程間通訊(IPC)機制。
- I/O 多路複用。在這種形式的併發編程中,應用程序在一個進程的上下文中顯式地調度它們本身的邏輯流。邏輯流被模型化爲狀態機,數據到達文件描述符後,主程序顯式地從一個狀態轉換到另外一個狀態。由於程序是一個單獨的進程,因此全部的流都共享同一個地址空間。
- 線程。線程是運行在一個單一進程上下文中的邏輯流,由內核進行調度。是其餘兩種方式的混合體,像進程流同樣由內核進行調度,而像I/O 多路複用流同樣共享同一個虛擬地址空間
基於進程的併發進程
基於進程的併發服務器
- 首先,包括一個SIGCHLD處理程序,回收僵死子進程資源
- 其次,父子進程必須關閉它們各自的connfd拷貝,以避免存儲器泄露
- 最後,知道父子進程的connfd都關閉了,到客戶端的鏈接纔會終止
構造併發程序最簡單的方法就是用進程
- 第一步:服務器接受客戶端的鏈接請求
- 第二步:服務器派生一個子進程爲這個客戶端服務
- 第三步:服務器接受另外一個鏈接請求
- 第四步:服務器派生另外一個子進程爲新的客戶端服務
進程的優劣
基於I/O多路複用的併發進程
I/O 多路複用技術基本的思路就是使用 select 函數,要求內核掛起進程,只有在一個或多個I/O事件發生後,纔將控制返回給應用程序。
服務器調用 select 函數來 檢測兩種不一樣類型的輸人事件:
- 來自一個新客戶端的鏈接請求到達
- 一個己存在的客戶 端的己鏈接描述符準備好能夠讀了。
基於I/O多路複用的併發事件驅動服務器
- 一個狀態機就是:狀態、輸入事件和轉移(狀態機sk)
- 狀態:等待描述符dk準備好可讀
- 輸入事件:描述符dk準備好能夠讀了
- 轉移:從描述符dk讀一個文本行
- 自循環是同一輸入和輸出狀態之間的轉移
I/O 多路複用技術的優劣
- 事件驅動設計的優勢:
- 它比基於進程的設計給了程序員更多的對程序行爲的控制。
- 一個基於 I/O 多路複用的事件驅動服務器是運行在單一進程上下文中的,因 此每一個邏輯流都能訪問該進程的所有地址空間。
- 缺點就是編碼複雜。咱們的事件驅動的併發 echo 服務器須要的代碼比基於進程的服務器多三倍。不幸的是,隨着併發粒度的減少,複雜性還會上升。這裏的粒度是指每一個邏輯流每一個時間片執行的指令數量。
基於線程的併發編程
- 線程(thread) 就是運行在進程上下文中的邏輯流。
- 每一個線程都有它本身的線程上下文 (thread context),包括一個惟一的整數線程 (Thread ID, TID)、棧、棧指針、程序計數器、通用目的寄存器和條件碼。全部的運行在一個進程裏的線程共享該進程的整個虛擬地址空間。
- 基於線程的邏輯流結合了基於進程和基於 I/O 多路複用的流的特性。同進程同樣,線程由內核自動調度,而且內核經過一個整數 ID 來識別線程。同基於 I/O 多路複用的流同樣,多個線程 運行在單一進程的上下文中,所以共享這個進程虛擬地址空間的整個內容,包括它的代碼、數據、堆、共享庫和打開的文件。
- 線程執行模型
- 主線程:每一個進程開始生命週期時第一個運行的線程
- 對等線程:某時刻主線程建立的
- 線程的上下文切換要比進程的上下文切換快得多。
- 和一個進程相關的線程組成一個對等(線程)池 (pool),獨立於其餘線程建立的線程。
- 線程不像進程同樣,不是按照嚴格的父子進程組織的
- 每一個對等線程都能讀寫相同共享數據
- Posix 線程
- Posix 線程 (Pthreads) 是在 C 程序中處理線程的一個標準接口。Pthreads 定義了大約 60 個函數,容許程序建立、殺死和回收線程,與對等線程安全地共享數據,還能夠通知對等線程系統狀態的變化。
- 線程的代碼和本地數據被封裝在一個線程例程(thread routine) 中。若是想傳遞多個參數給錢程例程,那麼你應該將參數放 到一個結構中,並傳遞一個指向該結構的指針。想要線程例程返回多個參數,你能夠返回一個指向一個結構的指針。
- 建立線程
- 線程經過調用pthread_create函數來建立其餘線程
- 新線程能夠經過調用pthread_self函數來得到它本身的線程ID
- 終止線程
- 當頂層的線程例程返回時,線程會隱式地終止。 經過調用 pthreadexit 函數,線程會顯式地終止。若是主線程調用 pthreadexit , 它會等待全部其餘對等線程終止,而後再終止主線程和整個進程,返回值爲 thread_return。
- 回收已終止線程的資源
- 線程經過調用pthread_join函數等待其餘線程終止
- 與wait函數不一樣,pthread_join函數只能等待一個指定的線程終止
- 分離線程
- 一個分離的線程是不能被其餘線程回收或殺死的。它的存儲器資源在它終止時由系統自動釋放
- 每一個可結合線程都應該要麼被其餘線程顯示的收回,要麼經過調用pthread_detach函數被分離
- pthreaddetach 函數分離可結合線程 tid. 線程可以經過以 pthreadself()爲參數的 pthread_detach 調用來分離它們本身。
- 初始化線程
- pthread_once 函數容許你初始化與線程例程相關的狀態。
- 一個基於線程的併發服務器
- 調用 pthread_ create 時,如何將已鏈接描述符傳遞給對等線程。最明顯的方法就是傳遞一個指向這個描述符的指針。 對等線程間接引用這個指針,並將它賦值給一個局部變量。
多線程程序中的共享變量
線程存儲器模型
- 一個變量是共享的,當且僅當多個線程引用這個變量的某個實例。
將變量映射到存儲器(根據存儲類型)
- 全局變量:全局變量是定義在函數以外的變量
- 本地自動變量:本地自動變量就是定義在函數內部可是沒有static屬性的變量
- 本地靜態變量:本地靜態變量是定義在函數內部有static屬性的變量
共享變量
- 變量是共享的:當且僅當它的一個實例被一個以上的線程引用。
用信號量同步線程
進度圖
- 進度圖是將n個併發線程的執行模型化爲一條n維笛卡爾空間中的軌跡線,原點對應於沒有任何線程完成一條指令的初始狀態。
- 當n=2時,狀態比較簡單,是比較熟悉的二維座標圖,橫縱座標各表明一個線程,而轉換被表示爲有向邊
- 轉換規則:
- 合法的轉換是向右或者向上,即某一個線程中的一條指令完成
- 兩條指令不能在同一時刻完成,即不容許出現對角線
- 程序不能反向運行,即不能出現向下或向左
- 而一個程序的執行歷史被模型化爲狀態空間中的一條軌跡線。
- 線程循環代碼的分解: H:在循環頭部的指令塊 L:加載共享變量cnt到線程i中寄存器%eax的指令。 U:更新(增長)%eax的指令 S:將%eax的更新值存回到共享變量cnt的指令 T:循環尾部的指令塊
- 臨界區:對於線程i,操做共享變量cnt內容的指令L,U,S構成了一個關於共享變量cnt的臨界區。
- 不安全區:兩個臨界區的交集造成的狀態
- 安全軌跡線:繞開不安全區的軌跡線
信號量
- 信號量實現互斥的基本原理
- 兩個或多個進程經過傳遞信號進行合做,能夠迫使進程在某個位置暫時中止執行(阻塞等待),直到它收到一個能夠「向前推動」的信號(被喚醒);
- 將實現信號燈做用的變量稱爲信號量,常定義爲記錄型變量s,其一個域爲整型,另外一個域爲隊列,其元素爲等待該信號量的阻塞進程(FIFO)。
- 使用信號量來實現互斥基本思想
- 將每一個共享變量(或者一組相關的共享變量)與一個信號量s(初始爲1)聯繫起來,而後用P和V操做將相應的臨界區包圍起來。
- 互斥鎖:以提供互斥爲目的的二元信號量
- 加鎖:一個互斥鎖上執行P操做稱爲對互斥鎖加鎖,執行V操做稱爲對互斥鎖解鎖。對一個互斥鎖加了鎖但尚未解鎖的線程稱爲佔用了這個互斥鎖。
- 計數信號量:一個唄用做一組可用資源的計數器的信號量
- wait(s)/signal(s)的應用
- 進程進入臨界區以前,首先執行wait(s)原語,若s.count<0,則進程調用阻塞原語,將本身阻塞,並插入到s.queue隊列排隊;
- 注意,阻塞進程不會佔用處理機時間,不是「忙等」。直到某個從臨界區退出的進程執行signal(s)原語,喚醒它;
- 一旦其它某個進程執行了signal(s)原語中的s.count+1操做後,發現s.count ≤0,即阻塞隊列中還有被阻塞進程,則調用喚醒原語,把s.queue中第一個進程修改成就緒狀態,送就緒隊列,準備執行臨界區代碼。
本週代碼託管
代碼託管連接
代碼量統計
學習進度條
目標 |
3500行 |
30篇 |
300小時 |
第一週 |
50/50 |
1/2 |
10/10 |
第二週 |
120/170 |
1/3 |
20/30 |
第三週 |
130/300 |
1/4 |
20/50 |
第五週 |
130/430 |
2/6 |
25/75 |
第六週 |
50/480 |
2/8 |
25/100 |
第七週 |
53/533 |
1/9 |
20/120 |
第八週 |
0/533 |
2/11 |
15/135 |
第九周 |
68/601 |
2/13 |
20/155 |
第十週 |
468/1069 |
1/15 |
20/175 |
十一週 |
404/1473 |
2/17 |
20/195 |
十二週 |
0/1473 |
2/19 |
15/210 |
十三週 |
1001/2474 |
1/20 |
20/230 |