天天看點

資訊安全系統設計基礎第十三周學習總結

第十二章 并發程序

使用應用級并發的應用程式稱為并發程式。

三種基本的構造并發程式的方法:程序,I/O多路複用,線程。

12.1 基于程序的并發程式設計

1.伺服器接受用戶端的連接配接請求

2.伺服器派生一個子程序為這個用戶端服務

3.伺服器接受另一個連接配接請求

4.伺服器派生另一個子程序為新用戶端服務

12.1.1 基于程序的并發伺服器

注意:

  1、由于伺服器通常會運作很長時間,是以要包括一個SIGCHILD處理程式來回收僵死的子程序資源。

  2、父子程序必須關閉他們各自的connfd拷貝,父程序必須關閉它的已連接配接描述符以避免存儲器洩露。

  3、父子程序的connfd都關閉了,到用戶端的連接配接才會終止。

12.1.2 關于程序的優劣

程序共享檔案表,不共享使用者位址空間,這樣一個程序不可能不小心覆寫另一個程序的虛拟儲存器,但是獨立的位址空間使得程序共享狀态資訊變得更加困難。

12.2 基于I/O多路複用的并發程序

I/O多路複用技術:使用select函數,要求核心挂起程序,隻有在一個或者多個I/O事件發生後,才将控制傳回給應用程式。

select 函數處理類型為 fd_set 的集合,也叫做描述符集合。邏輯上,我們将描述符集合看成一個大小為 n 的位向量。

每個位 bk對應于描述符 k。當且僅當 bk= 1, 描述符 k才表明是描述符集合的一個元素。隻允許你對描述符集合做三件事: 1) 配置設定它們, 2) 将一個此種類型的變量指派給另一個變量, 3) 用 FD_ZERO、 FD_SET、 FD_CLR 和 FD_ISSET 宏指令來修改和檢查它們。

select 函數有兩個輸人 : 一個稱為讀集合的描述符集合(fdset)和該 讀集合的基數 (n) (實際上是任何描述符集合的最大基數). select 函數會一直阻塞,直到讀集合中至少有一個描述符準備好可以讀。當且僅當一個從該描述符讀取一個位元組的請求不會阻塞時,描述符 k就表示準備好可以讀了。作為一個副作用, select 修改了參數 fdset 指向的 fd_set,指明讀集合中一個稱為準備好集合 (ready set) 的子集,這個集合是由讀集合中準備好可以讀了的描述符組成的。函數傳回的值指明了準備好集合的基數。由于這個副作用, 我們必須在每次調用 select 時都更新讀集合。

12.2.1 基于I/O多路複用的并發事件驅動伺服器

I/O 多路複用可以用做并發事件驅動程式的基礎,在事件驅動程式中,流是因為某種事件而前進的。一般概念是将邏輯流模型化為狀态機。

一個狀态機 就是一組狀态、輸入事件和轉移他,其中轉移就是将狀态和輸入事件映射到狀态。每個轉移都将一個(輸入狀态,輸入事件)對映射到一個輸出狀态。自循環是同一輸入和輸出狀态之間的轉移。把狀态機化成有向圖,其中節點表示狀态,有向弧表示轉移,而弧上的标号表示輸入事件。一個狀态機從某種初始狀态開始執行。每個輸入事件都會引發一個從目前狀态到下一狀态的轉移。

伺服器使用I/O多路複用,借助 select 函數檢測輸入事件的發生。

伺服器調用 select 函數來 檢測兩種不同類型的輸人事件: a) 來自一個新用戶端的連接配接請求到達, b) 一個己存在的用戶端的己連接配接描述符準備好可以讀了。

當一個連接配接請求到達時,伺服器打開連接配接,并調用add_client函數,将該使用者添加到池裡,最後,伺服器調用check_clients函數,把來自每個準備好的已連接配接描述符的一個文本行回送回去。

12.2.2 I/O多路複用技術的優劣

優點:

  1、給了程式員更多的對程式行為的控制。

  2、每個邏輯流都能通路該程序的全部位址空間,共享資料變得容易。

缺點:

  編碼複雜

12.3 基于線程的并發程式設計

線程:運作在程序上下文中的邏輯流。

12.3.1 線程執行模型

每個程序開始生命周期時都是單一線程,這個線程稱為主線程 。在某一時刻,主線程建立一個對等線程,從這個時間點開始,兩個線程就并發地運作。最後,因為主線程執行一個慢速系統調用。或者因為它被系統的間隔計時器中斷, 控制就會通過上下文切換傳遞到對等線程。對等線程會執行一段時間,然後控制傳遞回主線程,依次類推。

因為一個線程的上下文要比一個程序的上下文小得多,線程的上下文切換要比 程序的上下文切換快得多。另一個不同就是線程不像程序那樣,不是按照嚴格的父子層次來組織的。和一個程序相關的線程組成一個對等(線程)池 ,獨立于其他線程建立的線程。

主線程和其他線程的差別僅在于它總是程序中第一個運作的線程。對等 (線程)池概念的主要影響是,一個線程可 以殺死它的任何對等線程,或者等待它的任意對等線程終止。另外,每個對等線程都能讀寫相同的共享資料。

12.3.2 Posix 線程

Posix 線程是在C程式中處理線程的一個标準接口。Pthreads 定義了大約 60個函數,允許程式建立、殺死和回收線程,與對等線程安全地共享資料,還可以通知對等線程系統狀态的變化。

線程的代碼和本地資料被封裝在一個線程例程(thread routine) 中。如果想傳遞多個參數給錢程例程,那麼你應該将參數放到一個結構中,并傳遞一個指向該結構的指針。想要線程例程傳回多個參數,你可以傳回一個指向一個結構的指針。

12.3.3 建立線程

pthread_create函數建立一個新的線程,并帶着一個輸入變量arg,在新線程的上下文中運作線程示例f。能用attr參數來改變新建立線程的預設屬性。

當 pthread_create 傳回時,參數 tid包含新建立線程的ID。新線程可以通過調用 pthread_self 函數來獲得它自己的線程 ID.

12.3.4 終止線程

個線程是以下列方式之一來終止的 :

  1、當頂層的線程例程傳回時,線程會隐式地終止。

  2、通過調用 pthread_exit 函數,線程會顯式地終止。如果主線程調用 pthread_exit , 它會等待所有其他對等線程終止,然後再終止主線程和整個程序,傳回值為 thread_return。

  3、某個對等線程調用 Unix 的 exit 函數,該函數終止程序以及所有與該程序相關的線程。

  4、另一個對等線程通過以目前線程ID作為參數調用 pthread_cancle 函數來終止目前線程。

12.3.5 回收已終止線程的資源

線程通過調用 pthread_join 函數等待其他線程終止。

pthread_join 函數會阻塞,直到線程 tid 終止,将線程例程傳回的 (void*) 指針指派 為 thread_return 指向的位置,然後回收己終止線程占用的所有存儲器資源。

pthread join 函數隻能等待一個指定的線程終止。

12.3.6 分離線程

在任何一個時間點上,線程是可結合的或者是分離的。一個可結合的線程能夠被其他線程收回其資源和殺死。在被其他線程回收之前,它的存儲器資源(例如棧)是沒有被釋放的。相反,一個分離的線程是不能被其他線程回收或殺死的。它的存儲器資源在它終止時由系統自動釋放。

預設情況下,線程被建立成可結合的。為了避免存儲器洩漏,每個可結合線程都應該要麼被其他線程顯式地收回,要麼通過調用 pthread_detach 函數被分離。

pthread_detach 函數分離可結合線程 tid. 線程能夠通過以 pthread_self ()為參數 的 pthread_detach 調用來分離它們自己。

12.3.7 初始化線程

pthread_once 函數允許你初始化與線程例程相關的狀态。

once_control 變量是一個全局或者靜态變量,總是被初始化為 PTHREAD_ONCE_INIT。 當你第一次用參數 once_control 調用 pthread_once 時, 它調用 init_routine,這是一個沒有輸入參數,也不傳回什麼的函數。

動态初始化多個線程共享的全局變量時, pthread_once 函數是很有用的。

12.3.8 一個基于線程的并發伺服器

調用 pthread_ create 時,如何将已連接配接描述符傳遞給對等線程。最明顯的方法就是傳遞一個指向這個描述符的指針。

對等線程間接引用這個指針,并将它指派給一個局部變量。

這樣可能會出錯,因為它在對等線程的指派語句和主線程的 accept 語句間引入了競争。如果指派語句在下一個 accept 之前完成,那麼對等線程中的局部變量 connfd 就得到正确的描述符值。然而,如果指派語句是在 accept 之後才完成的,那麼對等線程中的 局部變量 connfd 就得到下一次連接配接的描述符值。那麼不幸的結果就是,現在兩個線程在同一 個描述符上執行輸入和輸出。

為了避免這種潛在的緻命競争,我們必須将每個 accept 傳回的已連接配接描述符配置設定到它自己的動态配置設定的存儲器塊是線上程例程中避免存儲器洩漏。既不顯式地收回線程,就必須分離每個線程,使得在它終止時它的存儲器資源能夠被收回。更進一步,我們必須小心釋放主線程配置設定的存儲器塊。

12.4 多線程程式中的共享變量

12.4.1 線程存儲器模型

一組并發線程運作在一個程序的上下文中。每個線程都有它自己獨立的線程上下文,包括線程 ID、棧、棧指針、程式計數器、條件碼和通用目的寄存器值。每個線程和其他線程一起共享程序上下文的剩餘部分。這包括整個使用者虛拟位址空間,它是由隻讀文本(代碼)、讀/寫資料、堆以及所有的共享庫代碼和資料區域組成的。線程也共享同樣的打開檔案的集合。

讓一個線程去讀或寫另一個線程的寄存器值是不可能的。另一方 面,任何線程都可以通路共享虛拟存儲器的任意位置。

儲存在虛拟位址空間的棧區域中,并且通常是被相應的線程獨立地通路的。

12.4.2 将變量映射到存儲器

線程化的 C 程式中變量根據它們的存儲類型被映射到虛拟存儲器:

全局變量。

本地自動變量。

本地靜态變量。

12.4.3 共享變量

一個變量 v 是共亭的,當且僅當它的一個執行個體被一個以上的線程引用。

12.5 用信号量同步線程

将線程 i 的循環代碼分解成五個部分:

  Hi:在循環頭部的指令塊

  Li:加載共享變量 cnt 到寄存器%eaxi 的指令,這裡%eaxi 表示線程i 中的寄存器%eax的值。

  Ui:更新(增加) %eaxi 的指令。

  Si:将%eaxi 的更新值存回到共享變量 cnt 的指令。

  Ti:循環尾部的指令塊。

注意頭和尾隻操作本地棧變量,而 Li、 Ui 和 Si操作共享計數器變量的内容。

一般而言, 你沒有辦法預測作業系統是否将為你的線程選擇一個正确的順 序。

進度圖 (progress graph) 的方法來闡明這些正确 的和不正确的指令順序的概念。

12.5.1 進度圖

進度圖将 n 個并發線程的執行模型化為一條 n 維笛卡兒空間中的軌迹線。每條軸 k對應于線程 k 的進度。每個代表線程 k 已經完成了指令 Ik 這一狀态。圖的原點對應于沒有任何線 程完成一條指令的初始狀态。

進度圖将指令執行模型化為從一種狀态到另一種狀态的轉換。轉換被表示為一條從一點到相鄰點的有向邊。合法的轉換是向右(線程 1 中的一條指令完成〉或者向上(線程 2 中的一條指令完成)的。兩條指令不能在同一時刻完成一一對角線轉換是不允許的。程式決不會反向運作,是以向下或者向左移動的轉換也是不合法的

一個程式的執行曆史被模型化為狀态空間中的一條軌迹線。

繞開不安全區的軌迹線叫做安全軌迹線。 相反,接觸到任何不安全區的軌迹線就叫做不安全軌迹線 。

12.5.2 信号量

一種解決同步不同執行線程問題的方法,這種方法是基于一種叫做信号量的特殊類型變量的。信号量 s 是具有非負整數值的全 局變量,隻能由兩種特殊的操作來處理,這兩種操作稱為 P 和 V:

P(s) :如果 s 是非零的,那麼 P 将 s 減1,并且立即傳回。如果 s 為零,那麼就挂起這個線程, 直到 s變為非零,而一個 V操 作會重新開機這個線程。在重新開機之後, P 操作将 s 減1,并将控制 傳回給調用者。

V(s): V操作将s 加 1。如果有 任何線程阻塞在P 操作等待 s 變成非零,那麼 V操作會重新開機這些線程中的一個,然後該線程将s減1,完成它的 P 操作。

12.5.3 使用信号量來實作互斥

基本思想是将每個共享變量 (或者一組相關的共享變量)與一個信号量 s (初始為1)聯系起來,然後用 P(s) 和V(s) 操作将 相應的臨界區包圍起來。

保護共享變量的信号量叫做二進制信号量 (binary semaphore),因為它的值總是 0 或者 1 。以提供互斥為目的的二進制信号量常常也稱為互斥鎖 (mutex)。在一個互斥鎖上執行 P 操作稱為對互斥鎖加鎖。類似地,執行 V操作稱為對互斥鎖解鎖。對一個互斥鎖加了鎖但是還沒有解鎖的線程稱為占用這個互斥鎖。一個被用作一組可用資源的計數器的信号量稱為計數信号量。

關鍵思想是這種 P 和 V操作的結合建立了一組狀态, 叫做禁止區 (forbidden region),其中 s<O。因為信号量的不變性,沒有實際可行的軌迹線能夠包含禁止區中的狀态。而且,因為禁止區完全包括了不安全區,是以沒有實際可行的軌迹線能夠接觸不安全區的任何部分。是以,每條實際可行的軌迹線都是安全的,而且不管運作時指令順序是怎樣的,程式都會正确地增加計數器的值。

使用信号量來互斥。 s<O 的不可行狀态定義了一個禁止區,禁止區完全包括了不安全 區,阻止了實際可行的軌迹線接觸到不安全區。

資訊安全系統設計基礎第十三周學習總結

由 P 和 V操作建立的禁止區使得在任何時間點上,在被包圍的臨界區中,不可能有多個線程在執行指令。換句話說,信号量操作確定了對臨界區的互斥通路。

12.5.4 利用信号量來排程共享資源

除了提供互斥之外,信号量的另一個重要作用是排程對共享資源的通路。

1. 生産者-消費者問題

生産者一消費者問題。生産者産生項目并把它們插入到一個有限的緩沖區中。消費者從緩沖區中取出這些項目,然後消費它們。

資訊安全系統設計基礎第十三周學習總結

因為插入和取出項目都涉及更新共享變量,是以我們必須保證對緩沖區的通路是互斥的。但是隻保證互斥通路是不夠的,我們還需要排程對緩沖區的通路。如果緩沖區是滿的(沒有空的槽位),那麼生産者必須等待直到有一個槽位變為可用。與之相似,如果緩沖區是空的(沒有可取用的項目),那麼消費者必須等待直到有一個項目變為可用。

使用SBUF構造生産者-消費者程式:基于預線程化的并發伺服器。

SBUP 操作類型為 sbuf_t 的有限緩沖區,項目存放在一個動态配置設定的 n 項整數數組 (buf) 中。 front 和 rear 索引值記錄該數組中的第一項和最後一項。三個信号量同步對緩 沖區的通路。 mutex 信号量提供互斥的緩沖區通路。 slots 和 items 信号量分别記錄空槽位和可用項目的數量。

資訊安全系統設計基礎第十三周學習總結

sbuf_init 函數為緩沖區配置設定堆存儲器,設定 front 和 rear 表示一個空的緩沖區,并為三個信号量賦初始值。這個函數在調用其他三個函數中的任何一個之前調用一次。

sbuf_deinit函數是當應用程式使用完緩沖區時,釋放緩沖區存儲的。 sbuf_insert 函數等待一個可用的槽位,對互斥鎖加鎖,添加項目,對互斥鎖解鎖,然後宣布有一個新項目可用。

sbuf_remove 函數是與 sbuf_insert 函數對稱的。在等待一個可用的緩沖區項目之後,對互斥鎖加鎖,從緩沖區的前面取出該項目,對互斥鎖解鎖,然後發信号通知一個新的槽位可供使用。

2、讀者-寫者問題

饑餓:一個線程無限期的阻塞,無法進展。

12.5.5 綜合: 基于預線程化的并發伺服器

預線程化的并發伺服器的組織結構。一組現有的線程不斷地取出和處理來自有限緩沖區的已連接配接描述符:

資訊安全系統設計基礎第十三周學習總結

12.7 其他并發問題

12.7.1 線程安全

一個線程是安全的,當且僅當被多個并發線程反複的調用時,它會一直産生正确的結果。

四個不相交的線程不安全函數類以及應對措施:

  不保護共享變量的函數——用P和V這樣的同步操作保護共享變量

  保持跨越多個調用的狀态的函數——從一個單線程中反複調用rand。

  傳回指向靜态變量的指針的函數——①重寫;②使用加鎖-拷貝技術。

  調用線程不安全函數的函數

12.7.2 可重入性

當它們被多個線程調用時,不會引用任何共享資料。

顯式可重入的:所有函數參數都是傳值傳遞,沒有指針,并且所有的資料引用都是本地的自動棧變量,沒有引用靜态或全劇變量。

隐式可重入的:調用線程小心的傳遞指向非共享資料的指針。

12.7.3 線上程化的程式中使用已存在的庫函數

使用線程不安全函數的可重入版本,名字以_r為字尾結尾。

12.7.4 競争

當一個程式的正确性依賴于一個線程要在另一個線程到達y 點之前到達它的控制流中的 x 點時,就會發生競争。

發生競争是因為程式員假定線程将按照某種特殊的軌迹線穿過執行狀态空間,而忘記了另一條準則規定:線程化的程式必須對任何可行的軌迹線都正确工作。

為了消除競争,可以動态的為每個整數ID配置設定一個獨立的塊,并且傳遞給線程例程一個指向這個塊的指針,注意線程例程必須釋放這些塊以避免存儲器洩露。

12.7.5 死鎖

信号量引人了一種潛在的令人厭惡的運作時錯誤,叫做死鎖(deadlock) ,它指的是一組線程被阻塞了,等待一個永遠也不會為真的條件。

  程式員使用 P 和 V操作順序不當,以至于兩個信号量的禁止區域重疊。如果某個執行軌迹 線碰巧到達了死鎖狀态 d,那麼就不可能有進一步的進展了,因為重疊的禁止區域阻塞了 每個合法方向上的進展。換句話說,程式死鎖是因為每個線程都在等待其他線程執行一個根本不可能發生的V操作。

  重疊的禁止區域引起了一組稱為死所區域的狀态。如果一個軌迹線碰巧到達了一個死鎖區域中的狀态,那麼死鎖就是不可避免的了。軌迹線可以進人死鎖區域, 但是它們不可能離開。

  死鎖是一個相當困難的問題,因為它不總是可預測的。一些幸運的執行軌迹線将繞開死鎖區域,而其他的将會陷入這個區域。

程式死鎖有很多原因,要避免死鎖一般而言是很困難的。然而,當使用二進制信号量來實作互斥時,可以應用下面的簡單而有效的規則來避免死鎖:

互斥鎖加鎖順序規則:如果對于程式中每對互斥鎖 (s, t), 每個同時占用 s 和 t 的線程都按照相同的順序對它們加鎖,那麼這個程式就是無死鎖的。

第十一章 網絡程式設計

一、用戶端-伺服器模型

1、當一個用戶端需要服務時,它向伺服器發送一個請求,發起一個事務。

2、伺服器收到請求後,解釋它,并以适當的方式操作它的資源。

3、伺服器給用戶端發送一個響應,并等待下一個請求。

4、用戶端收到響應并處理它

二、網絡

用戶端和伺服器通常運作在不同的主機上,并且通過計算機網絡的硬體和軟體資源來通信。

使用一些電纜和叫做網橋的小盒子,多個以太網段可以連接配接成較大的區域網路,稱為橋接以太網。

網橋比集線器更充分地利用了電纜帶寬。

多個不相容的區域網路可以通過叫做路由器的特殊計算機連接配接起來,組成一個internet(網際網路絡)。

三、全球ip網際網路

每台網際網路主機都運作實作 TCP/IP 協定的軟體,幾乎每個現代計算機系統都支援這個協定。

網際網路的用戶端和伺服器混合使用套接字接口函數和 Unix I/O 函數來進行通信。套接字函數典型地是作為會陷入核心的系統調用來實作的,并調用各種核心模式的 TCP/IP 函數。

1、ip位址

一個 IP 位址就是一個 32 位無符号整數。

htonl 函數将32 位整數由主機位元組順序轉換為網絡位元組順序。

ntohl 函數将 32 位整數從網絡宇節順序轉換為主機位元組。

htons和 ntohs 函數為 16 位的整數執行相應的轉換。

IP 位址通常是以一種稱為點分十進制表示法來表示的。

"n" 表示的是網絡(network)。"a" 表示應用(application)。而 "to" 表示轉換。

2、網際網路域名

網際網路用戶端和伺服器互相通信時使用的是 IP 位址。

子樹稱為子域。 層次結構中的第一層是 一個未命名的根節點。下一層是一組一級域名。

常見的第一層域名包括 com、 edu、 gov、org 和 net。

下一層是二級域名,例如 cmu. edu

一旦一個組織得到了一個二級域名,那麼它就可以在這個子域中建立任何新的域名了。

網際網路定義了域名集合和 IP 位址集合之間的映射。

網際網路應用程式通過調用 gethostbyname 和 gethostbyaddr 函數,從 DNS 資料庫中檢索任意的主機條目。

最簡單的情況下,一個域名和一個 IP 位址之間是一一映射的

某些情況下,多個域名可以映射為同一個 IP 位址

最通常的情況下,多個域名可以映射到多個 IP 位址

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

3、網際網路連接配接

網際網路用戶端和伺服器通過在連接配接上發送和接收位元組流來通信。

連接配接是點對點的。

從資料可以同時雙向流動的角度來說,它是全雙工的、可靠的。

Web 伺服器通常使用端口 80,而電子郵件伺服器使用端口 25。

四、套接字接口

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

1.socket函數

用戶端和伺服器使用 socket 函數來建立一個套接字描述符。

2.connect函數

用戶端通過調用 connect 函數來建立和伺服器的連接配接。

3.open_clientfd函數

open_clientfd 函數和運作在主機 hostname 上的伺服器建立一個連接配接,并在知名端口 port 上監聽連接配接請求。它傳回一個打開的套接宇描述符,該描述符準備好了,可以用 Unix I/O 函數做輸入和輸出。

4.bind函數

bind、 listen 和 accept 被伺服器用來和用戶端建立連接配接。

bind 函數告訴核心将 my_addr中的伺服器套接字位址和套接字描述符 sockfd 聯系起來。參數 addrlen 就是 sizeof(sockaddr_in) 。

5.listen函數

用戶端是發起連接配接請求的主動實體。伺服器是等待來自用戶端的連接配接請求的被動實體。預設情況下,核心會認為 socket 函數建立的描述符對應于主動套接字,它存在于一個連接配接的用戶端。

listen 函數将 sockfd 從一個主動套接字轉化為一個監聽套接字 (listening socket),該套接字可以接受來自用戶端的連接配接請求。

6.open_listenfd函數

socket、 bind 和 listen 函數結合成一個叫做。open_listenfd 的輔助函數。

7.accept函數

accept 函數來等待來自用戶端的連接配接請求。

accept 函數等待來自用戶端的連接配接請求到達偵聽描述符 listenfd,然後在 addr 中填寫用戶端的套接字位址,并傳回一個巳連接配接描述符,這個描述符可被用來利用 Unix I/O 函數與用戶端通信。

監聽描述符是作為用戶端連接配接請求的一個端點。

五、Web伺服器

1 、Web 基礎

Web 用戶端和伺服器之間的互動用的是一個基于文本的應用級協定,叫做 HTTP (Hypertext Transfer Protocol,超文本傳輸協定). HTTP 是一個簡單的協定。一個 Web 用戶端(即浏覽器) 打開一個到伺服器的網際網路連接配接,并且請求某些内容。伺服器響應所請求的内容,然後關閉連接配接。浏覽器讀取這些内容,并把它顯示在螢幕上。

2 、Web 内容

每條由 Web 伺服器傳回的内容都是和它管理的某個檔案相關聯的。這些檔案中的每一個都有一個唯一的名字,叫做 URL 。

3、 HTTP 事務

因為 HTTP 是基于在網際網路連接配接上傳送的文本行的,我們可以使用 Unix 的TELNET程式來和網際網路上的任何 Web 伺服器執行事務。

一個 HTTP 請求的組成是這樣的:一個請求行 (request line) ,後面跟随零個或更多個請求報頭 (request header),再跟随一個空的文本行來終止報頭清單

HTTP 支援許多不同的方法,包括 GET、 POST、 OPTIONS、 HEAD、 PUT、 DELETE 和 TRACE。

一個 HTTP 響應的組成是這樣的:一個響應行 (response line)後面跟随着零個或更多的響應報頭 (response header), 再跟随一個終止報頭的空行,再跟随一個響應主體 (response body)

狀态碼 (status code) 是一個三位的正整數, 指明對請求的處理。狀态消息 (status message) 給出與錯誤代碼等價的英文描述。

參考資料

教材