1. 程式人生 > >2017-2018 20155308 《信息安全系統設計基礎》第十四周學習總結

2017-2018 20155308 《信息安全系統設計基礎》第十四周學習總結

文件 byname 固定 提取 三種 n-1 v操作 完整 地址

2017-2018 20155308 《信息安全系統設計基礎》第十四周學習總結

教材第11章詳細總結及書上習題

客戶端-服務器編程模型

  • 每個網絡應用都是基於客戶端-服務器模型,一個應用是由一個服務器進程和一個或多個客戶端進程組成。服務器管理某種資源,並且通過操作這種資源來為他額客戶端提供某種服務。

  • 一個客戶端-服務器事務由四步組成:
  1. 當一個客戶端需要服務時,向服務器發送一個請求,發起一個事務。
  2. 服務器收到請求後,解釋它,並以適當的方式操作它的資源。
  3. 服務器給客戶端發送一個相應,並等待下一個請求。
  4. 客戶端收到響應並處理它。

技術分享圖片

網絡

  • 對主機而言,網絡是一種I/O設備,是數據源和數據接收方。

技術分享圖片

  • 物理上而言,網絡是一個按照地理遠近組成的層次系統。最低層是LAN(局域網),最流行的局域網技術是以太網。

  • 每個以太網適配器都有一個全球唯一的48位地址,它存儲在適配器的非易失性存儲器上。一臺主機可以發送一段位到這個網段內其它任何主機。每個幀包括一些固定數量的頭部位,用來標識此幀的源和目的地址及幀長此後緊隨的就是數據位有效載荷。每個主機適配器都能看到這個幀,但是只有目的主機能讀取。

  • 互聯網重要特性是它能由采用不同技術,互不兼容的局域網和廣域網組成,並能使其相互通信。
  • 協議提供的兩種基本能力
  1. 命名機制:
  2. 傳送機制:
  • 主機和路由器使用互連網絡協議在不兼容的局域網間傳送數據過程的8個基本步驟:
  1. 運行在主機A上的客戶端進行一個系統調用,從客戶端的虛擬地址空間復制數據到內核緩沖區中。
  2. 主機S上的協議軟件通過在數據前附加互聯網絡包頭和LAN1幀頭,創建一個LAN1的幀。
  3. LAN1適配器復制該幀到網絡上。
  4. 當此幀到達路由器時,路由器的LAN1適配器從電纜上讀取它,並把它傳送到協議軟件。
  5. 路由器從互聯網絡包頭中提取出目的互聯網絡地址,並用它作為路由表的索引,確定向哪裏轉發這個包。
  6. 路由器的LAN2適配器復制該幀到網絡上。
  7. 當此幀到達主機B時,它的適配器從電纜上讀到此幀,並將它傳送到協議軟件。
  8. 最後,主機B上的協議軟件剝落包頭和幀頭。

技術分享圖片

全球IP因特網

技術分享圖片

每臺因特網主機都運行實現TCP/IP協議,(傳輸控制協議/互聯網協議)的軟件,幾乎每個現代計算機系統都支持這個協議。

  • 把因特網看做一個世界範圍的主機集合,滿足以下特性:
  1. 主機集合被映射為一組32位的IP地址。
  2. 這組IP地址被映射為一組稱為因特網域名的標識符。
  3. 因特網主機上的進程能夠通過連接和任何其他主機上的進程。
  • 檢索並打印一個DNS主機條目:
#include "csapp.h"
int main(int argc, char **argv) 
{
    char **pp;
    struct in_addr addr;
    struct hostent *hostp;
    if (argc != 2) {
    fprintf(stderr, "usage: %s <domain name or dotted-decimal>\n", 
        argv[0]);
    exit(0);
    }
    if (inet_aton(argv[1], &addr) != 0) 
    hostp = Gethostbyaddr((const char *)&addr, sizeof(addr), AF_INET); 
    else                                
    hostp = Gethostbyname(argv[1]);
    printf("official hostname: %s\n", hostp->h_name);
    for (pp = hostp->h_aliases; *pp != NULL; pp++)
    printf("alias: %s\n", *pp);
    for (pp = hostp->h_addr_list; *pp != NULL; pp++) {
    addr.s_addr = ((struct in_addr *)*pp)->s_addr;
    printf("address: %s\n", inet_ntoa(addr));
    }
    exit(0);
}

IP地址

網絡程序將IP地址存放在所示IP地址結構中。

技術分享圖片

在IP地址結構中存放的地址總是一網絡字節順序存放的,即使主機字節順序是小端法。Unix提供了下面這樣的函數在網絡和主機字節順序見時間轉換。

技術分享圖片

應用程序使用以下函數來實現IP地址和點分十進制串之間的轉換。

技術分享圖片

  • 練習題11.1

技術分享圖片

答:

技術分享圖片

  • 練習題11.2

技術分享圖片

答:代碼如下

#include <stdio.h>
int ctoi(char ch)
{
    if(ch >= ‘a‘) return (10 + ch -‘a‘);
    return ch - ‘0‘;
}
void dex2dd(char *s)
{
    int n, flag = 0;
    char *p;
    p = s + 2;
    while(*p) {
        n = ctoi(*p) * 16 + ctoi(*++p) * 1;
        if(flag > 0) printf(".");
        printf("%d", n);
        p++; flag++;
    }
    printf("\n");
}
int main(int argc,char *argv[])
{
    dex2dd(argv[1]);
    return 0;
}
  • 練習題11.3

技術分享圖片

答:代碼如下

#include <stdio.h>
char a[10];
int ctoi(char ch)
{
    if(ch >= ‘a‘) return (10 + ch -‘a‘);
    return ch - ‘0‘;
}
//將十進制的正整數n轉換成base進制
void decimal(int n, int base)
{
    int r, i = 0;
    char c;
    if(n < 16) printf("0");
    do {
        r = n % base;
        c = r < 10 ? (r + ‘0‘) : (‘a‘ + r - 10);
        a[i++] = c;
        n = n / base;
    } while (n);
    while (i) printf("%c", a[--i]); 
}
void dd2hex(char *s)
{
    char *p, *q;
    int i, n, count;
    n = 0;
    p = q = s;
    printf("0x");
    while(*q && *p) {
        while(*q != ‘.‘ && *q) q++;
        count = q - p;
        for(i = 0; i < count; i++) {        
            n = n * 10 + ctoi(*p);
            p++;
        }
        decimal(n, 16);
        if(*q) { 
            q++;
            p = q;
        }
        n = 0;
    }
    printf("\n");
}
int main(int argc,char *argv[])
{
    dd2hex(argv[1]);
    return 0;
}

https://www.tuicool.com/articles/Nbym63R

因特網域名

  1. 每臺因特網主機都有本地定義的域名localhost,這個域名總是映射為回送地址127.0.0.1

技術分享圖片

  1. 使用HOSTNAME來確定本地主機的實際域名

技術分享圖片

  1. 最簡單的情況中,一個域名和一個IP地址之間一一映射

技術分享圖片

  1. 在某些情況下,多個域名可以映射為同一個IP地址

技術分享圖片

技術分享圖片

  1. 最通常情況下,多個域名可以映射到同一組的多個IP地址

技術分享圖片

技術分享圖片

  1. 某些合法的域名沒有映射到任何IP地址

技術分享圖片

套接字接口

套接字接口是一組函數,它們和Unix I/O函數結合起來,用於建立網絡應用。

技術分享圖片

?函數: ?socket函數
?connect函數
?open_clientfd函數
?bind函數
?listen函數
?open_listenfd函數
?accept函數

Web服務器

?Web客戶端和服務器之間的交互用的是一個基於文本的應用級協議,叫做 HTTP (Hypertext Transfer Protocol,超文本傳輸協議). HTTP 是一個簡單的協議。一個 Web 客戶端(即瀏覽器) 打開一個到服務器的因特網連接,並且請求某些內容。服務器響應所請求的內容,然後關閉連接。瀏覽器讀取這些內容,並把它顯示在屏幕上。
?Web內容可以用一種叫做 HTML(Hypertext Markup Language,超文本標記語言)的語言來編寫。一個 HTML 程序(頁)包含指令(標記),它們告訴瀏覽器如何顯示這頁中的各種文本和圖形對象。
?Web 服務器以兩種不同的方式向客戶端提供內容: ?取一個磁盤文件,並將它的內容返回給客戶端。磁盤文件稱為靜態內容 (static content), 而返回文件給客戶端的過程稱為服務靜態內容 (serving static content)。
?運行一個可執行文件,並將它的輸出返回給客戶端。運行時可執行文件產生的輸出稱為態內容 (dynamic content),而運行程序並返回它的輸出到客戶端的過程稱為服務動態內容 (serving dynamic content)。

並發編程
?並發:邏輯控制流在時間上重疊
?並發程序:使用應用級並發的應用程序稱為並發程序。
?三種基本的構造並發程序的方法: ?進程,用內核來調用和維護,有獨立的虛擬地址空間,顯式的進程間通信機制。
?I/O多路復用,應用程序在一個進程的上下文中顯式的調度控制流。邏輯流被模型化為狀態機。

?線程,運行在一個單一進程上下文中的邏輯流。由內核進行調度,共享同一個虛擬地址空間。

基於進程的並發編程
?構造並發服務器的自然方法就是,在父進程中接受客戶端連接請求,然後創建一個新的子進程來為每個新客戶端提供服務。
?因為父子進程中的已連接描述符都指向同一個文件表表項,所以父進程關閉它的已連接描述符的拷貝是至關重要的,而且由此引起的存儲器泄露將最終消耗盡可用的存儲器,使系統崩潰。
?基於進程的並發echo服務器的重點內容: ?需要一個SIGCHLD處理程序,來回收僵死子進程的資源。
?父子進程必須關閉各自的connfd拷貝。對父進程尤為重要,以避免存儲器泄露。
?套接字的文件表表項中的引用計數,直到父子進程的connfd都關閉了,到客戶端的連接才會終止。

?進程的模型:共享文件表,但不是共享用戶地址空間。
?關於進程的優劣: ?優點:一個進程不可能不小心覆蓋兩一個進程的虛擬存儲器。
?缺點:獨立的地址空間使得進程共享狀態信息變得更加困難。進程控制和IPC的開銷很高。
?Unix IPC是指所有允許進程和同一臺主機上其他進程進行通信的技術,包括管道、先進先出(FIFO)、系統V共享存儲器,以及系統V信號量。

基於I/O多路復用的並發編程
?echo服務器必須響應兩個相互獨立的I/O時間: ?網絡客戶端發起連接請求
?用戶在鍵盤上鍵入命令行

?I/O多路復用技術的基本思路:使用select函數,要求內核掛起進程,只有在一個或多個I/O事件發生後,才將控制返回給應用程序。
?將描述符集合看成是n位位向量:b(n-1),……b1,b0 ,每個位bk對應於描述符k,當且僅當bk=1,描述符k才表明是描述符集合的一個元素。可以做以下三件事: ?分配它們;
?將一個此種類型的變量賦值給另一個變量;
?用FDZERO、FDSET、FDCLR和FDISSET宏指令來修改和檢查它們。

?echo函數:將來自科幻段的每一行回送回去,直到客戶端關閉這個鏈接。

?狀態機就是一組狀態、輸入事件和轉移,轉移就是將狀態和輸入時間映射到狀態,自循環是同一輸入和輸出狀態之間的轉移。
?事件驅動器的設計優點: ?比基於進程的設計給了程序員更多的對程序行為的控制
?運行在單一進程上下文中,因此,每個邏輯流都能訪問該進程的全部地址空間,使得流之間共享數據變得很容易。
?不需要進程上下文切換來調度新的流。

?缺點: ?編碼復雜
?不能充分利用多核處理器

?粒度:每個邏輯流每個時間片執行的指令數量。並發粒度就是讀一個完整的文本行所需要的指令數量。

基於線程的並發編程
?線程:運行在進程上下文中的邏輯流。

?線程有自己的線程上下文,包括一個唯一的整數線程ID、棧、棧指針、程序計數器、通用目的寄存器和條件碼。所有運行在一個進程裏的線程共享該進程的整個虛擬地址空間。

線程執行模型

?主線程:每個進程開始生命周期時都是單一線程。
?對等線程:某一時刻,主線程創建的對等線程 。
?線程與進程的不同: ?線程的上下文切換要比進程的上下文切換快得多;
?和一個進程相關的線程組成一個對等池,獨立於其他線程創建的線程。
?主線程和其他線程的區別僅在於它總是進程中第一個運行的線程。

?對等池的影響 ?一個線程可以殺死它的任何對等線程;
?等待它的任意對等線程終止;

?每個對等線程都能讀寫相同的共享資源。

Posix線程

?線程例程:線程的代碼和本地數據被封裝在一個線程例程中。每一個線程例程都以一個通用指針作為輸入,並返回一個通用指針。

創建線程

?pthread create函數創建一個新的線程,並帶著一個輸入變量arg,在新線程的上下文中運行線程例程f。新線程可以通過調用pthread _self函數來獲得自己的線程ID。

終止線程

?一個線程的終止方式: ?當頂層的線程例程返回時,線程會隱式的終止;

?通過調用pthread _exit函數,線程會顯示地終止。如果主線程調用pthread _exit,它會等待所有其他對等線程終止,然後再終止主線程和整個進程。

回收已終止線程的資源

?pthread _join函數會阻塞,直到線程tid終止,回收已終止線程占用的所有存儲器資源。pthread _join函數只能等待一個指定的線程終止。

分離線程
?在任何一個時間點上,線程是可結合的或者是分離的。一個可結合的線程能夠被其他線程收回其資源和殺死;一個可分離的線程是不能被其他線程回收或殺死的。它的存儲器資源在它終止時有系統自動釋放。
?默認情況下,線程被創建成可結合的,為了避免存儲器漏洞,每個可集合的線程都應該要麽被其他進程顯式的回收,要麽通過調用pthread _detach函數被分離。

初始化線程
?pthread _once函數允許初始化與線程例程相關的狀態。
?once _control變量是一個全局或者靜態變量,總是被初始化為PTHREAD _ONCE _INIT.

一個基於線程的並發服務器
?對等線程的賦值語句和主線程的accept語句之間引入了競爭。

多線程程序中的變量共享

線程存儲器模型
?每個線程和其他線程一起共享進程上下文的剩余部分。包括整個用戶虛擬地址空間,是由只讀文本、讀/寫數據、堆以及所有的共享庫代碼和數據區域組成的。線程也共享同樣的打開文件的集合。

?任何線程都可以訪問共享虛擬存儲器的任意位置。寄存器是從不共享的,而虛擬存儲器總是共享的。

將變量映射到存儲器

?全局變量:虛擬存儲器的讀/寫區域只會包含每個全局變量的一個實例。
?本地自動變量:定義在函數內部但沒有static屬性的變量。

?本地靜態變量:定義在函數內部並有static屬性的變量。

共享變量

?變量v是共享的,當且僅當它的一個實例被一個以上的線程引用。

用信號量同步線程
?共享變量引入了同步錯誤的可能性。
?線程i的循環代碼分解為五部分: ?Hi:在循環頭部的指令塊
?Li:加載共享變量cnt到寄存器%eax的指令,%eax表示線程i中的寄存器%eax的值
?Ui:更新(增加)%eax的指令
?Si:將%eaxi的更新值存回到共享變量cnt的指令
?Ti:循環尾部的指令塊。

進度圖
?進度圖將指令執行模式化為從一種狀態到另一種狀態的轉換。轉換被表示為一條從一點到相鄰點的有向邊。合法的轉換是向右或者向上。
?臨界區:對於線程i,操作共享變量cnt內容的指令構成了一個臨界區。
?互斥的訪問:確保每個線程在執行它的臨界區中的指令時,擁有對共享變量的互斥的訪問。
?安全軌跡線:繞開不安全區的軌跡線
不安全軌跡線:接觸到任何不安全區的軌跡線就叫做不安全軌跡線
?任何安全軌跡線都能正確的更新共享計數器。

信號量
?當有多個線程在等待同一個信號量時,你不能預測V操作要重啟哪一個線程。
?信號量不變性:一個正在運行的程序絕不能進入這樣一種狀態,也就是一個正確初始化了的信號量有一個負值。

使用信號量來實現互斥
?二元信號量:將每個共享變量與一個信號量s聯系起來,然後用P(S)和V(s)操作將這種臨界區包圍起來,這種方式來保護共享變量的信號量。
?互斥鎖:以提供互斥為目的的二元信號量
?加鎖:一個互斥鎖上執行P操作稱為對互斥鎖加鎖,執行V操作稱為對互斥鎖解鎖。對一個互斥鎖加了鎖但還沒有解鎖的線程稱為占用了這個互斥鎖。
?計數信號量:一個唄用作一組可用資源的計數器的信號量

利用信號量來調度共享資源
?信號量的作用:(1)提供互斥(2)調度對共享資源的訪問
?生產者—消費者問題:生產者產生項目並把他們插入到一個有限的緩沖區中,消費者從緩沖區中取出這些項目,然後消費它們。
?讀者—寫者問題: ?讀者優先,要求不讓讀者等待,除非已經把使用對象的權限賦予了一個寫者。
?寫者優先,要求一旦一個寫者準備好可以寫,它就會盡可能地完成它的寫操作。
?饑餓就是一個線程無限期地阻塞,無法進展。

使用線程提高並行性
?寫順序程序只有一條邏輯流,寫並發程序有多條並發流,並行程序是一個運行在多個處理器上的並發程序。並行程序的集合是並發程序集合的真子集。

其他並發問題

線程安全
?線程安全:當且僅當被多個並發線程反復地調用時,它會一直產生正確的結果。
?線程不安全:如果一個函數不是線程安全的,就是線程不安全的。
?線程不安全的類: ?不保護共享變量的函數
?保持跨越多個調用的狀態的函數。
?返回指向靜態變量的指針的函數。解決辦法:重寫函數和加鎖拷貝。
?調用線程不安全函數的函數。

可重入性
?可重入函數:當它們被多個線程調用時,不會引用任何共享數據。可重入函數是線程安全函數的一個真子集 。
?關鍵思想是我們用一個調用者傳遞進來的指針取代了靜態的next變量。
?顯式可重入:沒有指針,沒有引用靜態或全局變量
?隱式可重入:允許它們傳遞指針
?可重入性即使調用者也是被調用者的屬性,並不只是被調用者單獨的屬性。

在線程化的程序中使用已存在的庫函數
?使用線程不安全函數的可重入版本,名字以_r為後綴結尾。

競爭
?競爭:當一個程序的正確性依賴於一個線程要在另一個線程到達y點之前到達它的控制流中的x點時,就會發生競爭。
?線程化的程序必須對任何可行的軌跡線都正確工作。
?消除方法:動態的為每個整數ID分配一個獨立的塊,並且傳遞給線程例程一個指向這個塊的指針

死鎖
?死鎖:一組線程被阻塞了,等待一個永遠也不會為真的條件。
?程序員使用P和V操作不當,以至於兩個信號量的禁止區域重疊。
?重疊的禁止區域引起了一組稱為死鎖區域的狀態。
?死鎖是不可預測的。

2017-2018 20155308 《信息安全系統設計基礎》第十四周學習總結