Http報文
HTTP請求報文由請求行、請求頭部、空行和請求包體4個部分組成,如下圖所示:
1.1、通用報文
- General: //通用報文
- Request Method: GET
- Status Code: 200 OK
- Remote Address: 47.111.45.248:80
- Referrer Policy: origin
1.2、請求報文
- Request Headers: //客戶端請求頭
- Accept : image/webp,image/apng,image/*,*/*;q=0. //瀏覽器客戶端告訴告訴服務端能接受什么樣類型的數據
- Accept-Encoding: gzip, deflate //瀏覽器客戶端告訴服務器能接受什么編碼格式,包括字符編碼,壓縮方式
- Accept-Language: zh-CN,zh;q=0.9 //客戶端告訴瀏覽器接受什么樣的語言
- Accept-Ranges: bytes //斷點續傳
- ETag: "23411b8a827d31:0”. //304
- Cache-Control : no-cache
- Connection : keep-alive //客戶端告訴服務端的連接方式: 長連接
- X-UA-Compatible: IE=10
- X-Frame-Options: SAMEORIGIN
- Cookie: _ga=GA1.2.1796862747.1547952793; __gads=ID=60d16307ea494dae:T=1547952794:S=ALNI_MYsoIBtEfg7-PJNMTds68JgtxnQrw; UM_distinctid=168832d7c157de-0ad85a26ff65a-35617601-13c680-168832d7c168b3;
- Host: www.cnblogs.com。 //要請求的主機及端口 目的地
- Pragma: no-cache
- Referer: http://www.cnblogs.com/ //客戶端告訴瀏覽器這個請求是從哪里過來的,請求來源
- User-Agent: Mozilla/5.0 (macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (Khtml, like Gecko) Chrome/73.0.3683.86 Safari/537.36。 //瀏覽器指定,告訴服務器,使用的瀏覽器的版本和名稱自動發送
1.3、響應報文
- Response Headers: //服務器返回http頭
- HTTP/1.1 200 OK
- Date: Tue, 16 Apr 2019 05:13:48 GMT //什么時候響應會瀏覽器
- Content-Type : image/x-icon。 //響應的內容是什么類型,采用的是什么編碼, 對應請求的accept設置內容
- Content-Length : 1332 //服務端告訴瀏覽器相應實體的大小
- Connection: keep-alive /close //服務端告訴瀏覽器連接的方式為長連接, 管道連接,異步響應http的請求,http1.1,提高效率;
- Cache-Control : max-age=120. //服務端告訴瀏覽器緩存的時間最長為120s
- Last-Modified : Fri, 28 Jul 2017 09:18:56 GMT //服務器文本最后一次修改的時間. 304
ps:在實際情況中使用: response.setContentType("text/html;charset=UTF-8”); 來設置編碼以解決中文的亂碼問題。
(0)、Connection: keep-alive /close 服務端告訴瀏覽器連接的方式為長連接, 管道連接,異步響應http的請求,http1.1,提高效率;
(1)、MIME Type:是描述消息內容類型的因特網標準, 常見的數據幾種類型
- 文本文件:text/html,text/plain,text/css,application/xhtml+xml,application/xml
- 圖片文件:image/jpeg,image/gif,image/png.
- 視頻文件:video/mpeg,video/quicktime
我們可以通過兩種方式來設置文件的渲染類型,
- 第一種是 Accept-客戶端
- 第二種是 Content-Type-服務器
Accept : 表示 客戶端希望接受的數據類型,即告訴服務器我需要什么媒體類型的數據,此時 服務器應該根據 Accept 請求頭生產指定媒體類型的數據。
Content-Type : 表示發送端發送的實體數據類型,比如我們應該寫過類似的: resposne.setContentType(“application/json;charset=utf-8”)的代碼,表示服務端返回的數據 格式是 json。
如果 Accept 和 Content-Type 不一致,假如說 Accept 要接收的類型是 image/gif,但是服務 端返回的數據是 text/html,那么瀏覽器將會無法解析。
(2) .Cache-Control 作用:
客戶端瀏覽器用來判斷是否需要用本地緩存。 默認值為private;常用值有private、no-cache、max-age、must-revalidate。
具體場景舉例:
a.打開新窗口時值為 private、no-cache、must-revalidate ,那么打開新窗口訪問時都會重新訪問服務器。而如果指定了 max-age 和 expire 值(單位為秒),那么在此值內的時間里就不會重新訪問服務器:
例如:Cache-control: max-age=5(表示當訪問此網頁后的5秒內再次訪問不會去服務器)
b.在地址欄回車.值為 private或must-revalidate則只有第一次訪問時會訪問服務器,以后就不再訪問。
值為 no-cache,那么每次都會訪問。
值為 max-age 和 expire,則在過期之前不會重復訪問。
c.按后退按扭
值為private、must-revalidate、max-age,則不會重訪問,
值為no-cache,則每次都重復訪問
d.按刷新按鈕
無論為何值,都會重復訪問;
(3) 、Cookie 作用:客戶端瀏覽器用來存儲一些用戶信息以便讓服務器辨別用戶身份的(大多數需要登錄的網站上面會比較常見),比如用戶名和密碼,sessionId等。
(4) 、If-Modify-Since 作用:
把瀏覽器端緩存頁面的最后修改時間(精確到秒)發送到服務器去,服務器會把這個時間與服務器上實際文件的最后修改時間進行對比。如果時間一致,那么返回304,客戶端就直接使用本地緩存文件。如果時間不一致,就會返回200和新的文件內容以及新的修改時間(Last-Modify)。客戶端接到之后,會丟棄舊文件,把新文件緩存起來,并顯示在瀏覽器中。
(5) 、Etag的使用場景:
1.有些文件需要頻繁更新,但是文件內容并沒有變化。
聰明的開發者會把 Last-Modified和ETags請求的http報頭一起使用,提高瀏覽器性能。這樣可利用客戶端(例如瀏覽器)的緩存。因為服務器首先產生Last-Modified/Etag標記,服務器可在稍后使用它來判斷頁面是否已經被修改。本質上,客戶端通過將該記號傳回服務器要求服務器驗證其(客戶端)緩存。
過程如下:
- 1.客戶端請求一個頁面(A)。
- 2.服務器返回頁面A,并在給A加上一個Last-Modified/ETag。
- 3.客戶端展現該頁面,并將頁面連同Last-Modified/ETag一起緩存。
- 4.客戶再次請求頁面A,并將上次請求時服務器返回的Last-Modified/ETag一起傳遞給服務器。
- 5.服務器檢查該Last-Modified或ETag,并判斷出該頁面自上次客戶端請求之后還未被修改,直接返回響應304和一個空的響應體。
(6) 、如果服務器又設置了Cache-Control:max-age和Expires呢,怎么辦?
答案是同時使用,也就是說在完全匹配If-Modified-Since和If-None-Match即檢查完修改時間和Etag之后,服務器才能返回304.(不要陷入到底使用誰的問題怪圈)
(7) 、如果傳輸的文件很大怎么辦?
方案一:通過壓縮文件: Accept-Encoding: gzip , deflate ;
方案二:分割傳輸,瀏覽器逐步顯示;
狀態碼
1XX : 接受的請求正在處理
200: 請求正常處理
3xx開頭,資源文件
301: 資源被永久刪除,永久重定向到新的網址
302: 舊的資源還在,只是暫時性的重定向資源
重定向原因:
(1)網站調整(如改變網頁目錄結構);
(2)網頁被移到一個新地址;
(3)網頁擴展名改變(如應用需要把.php改成.Html或.shtml)。
- 304: 返回上次請求資源未作改動,驗證瀏覽器的緩存機制 Etag
- 307: 資源的重定向,但是不會把post改為get操作;
- 4xx開頭:客戶端
- 400: 請求參數錯誤
- 401: 客戶端無權訪問,要去輸入用戶名密碼之類的授權信息
- 403: 禁止訪問(讀寫權限等影響)
- 404: 請求的資源不存在
- 5xx開頭:服務端
- 500: 服務內部錯誤
- 502: 網關錯誤
- 503: 臨時過載或者維護,導致服務端無法正常處理請求
擁塞
計算機網絡中的帶寬,交換節點中的緩存和處理機制,都是網絡資源。在某段時間內,若對網絡中某一資源的需求超過了該資源所能提供的可用部分,網絡的性能就會變壞。
這種情況就叫做擁塞。 擁塞發生的主要原因是網絡能夠提供的資源不足以滿足用戶的需求,這些資源包括緩存空間、鏈路帶寬容量和中間節點的處理能力。
由于互聯網的設計機制(任何人任何時間都能共享網絡資源)導致其缺乏“接納控制”能力,因此在網絡資源不足時不能限制用戶數量,只能靠降低服務質量來繼續為用戶服務,也就是“盡力而為”服務。但是也不是說增加網絡資源,就可以避免網絡擁塞。
擁塞雖然是由于網絡資源的缺乏引起的, 但是單純增加資源并不能避免擁塞的發生。有時增加緩存空間到一定程度時,只會加重擁塞,而不是減輕擁塞,這是因為當數據包經過長期時間排隊完成轉發時,他們可能早已經超時,從而引起源端超時重發,而這些數據包還會繼續傳輸到下一個路由器,從而浪費網絡資源,加重網絡擁塞。事實上, 緩存空間不足導致的丟包更多的是擁塞的“癥狀”而非原因。
另外,增加鏈路寬帶及提高處理能力也不能解決擁塞問題。
例如我們有4臺ABCD主機和一個路由,所有的鏈路帶寬都是1Gbps,如果A和B 同時以1Gbps的速率發送數據,則路由器的輸入速率為2Gpbs,從而產生擁塞。避免擁塞的方法是控制AB的發送速率,例如AB都是0.5Gpbs,但是如果此時D也以1Gpbs的速率發送,那么擁塞還是無法避免,況且用戶主機不可能只有4個。 所以說擁塞只是一個動態問題,我們沒有辦法用一個靜態方案去解決,從這個意義上說,擁塞是不可避免的!!
擁塞是一個全局控制的過程,他不像點對點的流控機制,是一個局部的控制!
TCP的擁塞控制算法
TCP的擁塞控制由4個核心的算法組成: 慢啟動(slow start)、擁塞避免(Congestion voidance)、快速重傳(Fast Retransmit)和快速恢復(Fast Recovery)。
擁塞控制,在發送方維持著一個擁塞窗口cwmd(congestion window)的狀態量。擁塞窗口的大小取決于網絡的擁塞程度,并且動態的變化。發送方讓自己的發送窗口等于擁塞窗口,另外考慮到接收方的接收能力,發送窗口可能小于擁塞窗口。
4.1、慢啟動(slow start)
早期的開發的TCP應用在啟動一個連接時會向網絡中發送大量的數據包,這樣很容易導致路由器緩存空間耗盡,網絡發生擁塞,使得TCP連接的吞吐量急劇下降。由于TCP源端一開始并不知道網絡資源當前的利用狀況,因此新建立的TCP連接不能一開始就發送大量的數據,而只能逐步增加每次發送的數據量,以避免上述現象的發生。具體來說,當新建立一個連接時,CWND初始化為1個最大報文段(MSS)大小,發送端開始按照擁塞窗口大小發送數據,每當有一個報文被確認,cwnd就增加1個MSS大小。這樣cwnd的值就隨著網絡往返時間(Round trip time,RTT)呈指數級增長,事實上,慢啟動的速度一點也不慢,只是他的起點比較低一點兒而已,指數級的增長率是十分快的。
該算法的思想主要是一種探測一下網路的擁塞程度,就是不要一開始就發送大量的數據,也就是說有小到大逐漸增加(指數)擁塞窗口的大小。
我們可以簡單計算:
- 開始cwnd=1
- 經過1個RTT后, cwnd=2*1=2
- 經過2個RTT后, cwnd=2*2=4
- 經過3個RTT后, cwnd=2*4=8
- 如果寬帶為W,那么經過RTT*log2W時間就可以占滿帶寬;
4.2、擁塞避免(Congestion voidance)
如果按上述的慢啟動的思想如果不加以控制的話,毫無疑問地發生網絡擁塞,當cwnd很快增長上來的時候,也很快利用了網絡的資源,但是cwnd不能一直這樣增長,一定需要某個限制。TCP使用了一個慢啟動門限(ssthresh)的變量,當cwnd超過該值后,慢啟動結束,進入擁塞避免階段。對于大多數的TCP是吸納來說,ssthresh的值是65535(同樣以16bit來計算)。擁塞避免的思想就是轉指數增大變為加法線性增大。這樣就可以避免增長過快導致網絡擁塞,慢慢地增加調整到網絡的最佳值。
期具體ssthresh的用法如下:
- 當cwnd<ssthresh時,使用慢開始算法。
- 當cwnd>ssthresh時,改用擁塞避免算法。
- 當cwnd=ssthresh時,慢開始與擁塞避免算法任意。
注意:如果當前的cwnd達到慢啟動的閾值,則試探性的發送一個segment,如果服務器沒有響應,TCP認為網絡能力下降,必須降低慢啟動閾值,同時為了避免形式繼續惡化,有可能將窗口降低為1
4.3、快速重傳(Fast Retransmit)
正常情況下,按照上一節講的消息重傳是等到定時器超時(RTO)后在重傳,但有時候不需要等那么久也可以重傳。比如客戶端向服務器發送了5個段數據包。第三個丟失,其他正常,那么客戶端會收到3個包2的ACK,而4、5正常到達后會被服務器緩存起來但是不會發送相應包的ACK,因為TCP是基于積累確認機制,以確保丟失的包能被重發,數據接收準確,ACK必須是連續的。這個時候就不必在等待RTO的超時時間了,服務器判斷已經丟失了就可以馬上快速重傳,提高效率。
快速重傳算法規定,發送方只要一連收到三個重復確認就應當立即重傳對方尚未收到的報文文件,而不必繼續等待設置重傳計時器時間到期。
4.4、快速恢復(Fast Recovery)
其實快速恢復并不是單獨存在的,它是快速重傳的后續處理。通常認為客戶端接收到3個ACK后,就會開始快速重傳,但是如果還有更多的重復ACK呢,這個時候就是快速恢復要做的。
a、當發送方連續收到三個重復確認時,就執行“乘法減小”算法,把ssthresh門限減半(也即cwnd=ssthresh/2).但是接下去并不執行慢開始算法;
b、考慮到此時能連續收到3個ACK,說明網絡沒有擁塞,執行加法原則,有幾個ACK就加幾個段的字節數, 或者可以將cwnd=ssthresh,直接進入擁塞避免算法。
四種算法相互間的合作運行圖如下所示:
問題思考
問題一:如何檢測擁塞?
首先來看一下TCP是如何確定網絡進入擁塞的,TCP認為網絡擁塞的主要依據是它重傳了一個報文段。上面提到過,TCP對每一個報文段都有一個定時器,稱為重傳定時器(RTO),當RTO超時且還沒有得到數據確認,那么TCP就會對該報文段進行重傳,當發生超時時,那么出現擁塞的可能性就很大,某個報文段可能在網絡中某處丟失,并且后續的報文段也沒有了消息,在這種情況下,TCP反應比較“強烈”:
- (1)把ssthresh降低為cwnd值的一半;
- (2)把cwnd重新設置為1;
- (3)重新進入慢啟動過程;
可以看出,從整體上講,TCP擁塞控制窗口變化的原則是: AIMD(Additive Increase Multiplicative Decrease)。TCP/IP模型中,屬于運輸層,即:加性增,乘性減, 或者叫做“和式增加,積式減少”。該原則很好地保證了流之間的公平性,因為一旦出現丟包,那么立即減半退避,可以給其他新建的流留有足夠的空間,從而保證整個的公平性。
問題二:為什么客戶端沒接收到一個ACK,會把cwnd增加一個segment呢?
這是基于管道模型的“數據包守恒”原則,及同一時刻在網絡中傳輸的數據包數量是恒定的,只有當“舊”數據包離開網路后,才能發送“新”數據包進入網絡。如果發送方收到一個ACK,則認為有一個數據已經離開了網絡,于是將擁塞窗口+1,如果網路能夠嚴格遵守該“數據包守恒”原則,則擁塞的法神會大大減少。
有趣的聯想: TCP擁塞的解決就像是我們生活中的交通堵車?
其中有兩個原則:
一、擁塞不可避免,單純增加資源并不能避免擁塞的發生;
二、數據包守恒原則。如果政府只是花資金修路,拓寬公路,并不能避免堵車,因為車的數量是不定的,旅游季可能有很多,也許一時間段沒有車,這時候只能從源頭控制。對車流量進行控制:例如限制車輛進入主公路,根據實際的情況,如果某一時間段車輛少,則可以慢慢增加車輛進入該公路段,但是當達到一個 閾值,就要放緩車輛進入的速度,并實時地探測整條路的狀況,如果情況緊急,則立刻將車流量減少一半,將車流量降到最低,然后在重新回到慢啟動轉態。使整條公路能夠保持暢通,達到最大的運行效率。