經(jīng)過面試的同學(xué)經(jīng)常會(huì)遇到這樣的問題: 你是如何理解TCP/IP協(xié)議的?
回答:通訊協(xié)議?三次握手 ? 四次揮手? 一臉懵逼!
如果你感覺已經(jīng)被上述情景安排,那么有必要好好看看這篇文章。
另外附上一篇tcp/ip面試中的問題視頻解答:面試中tcpip,哪些容易被問到的及解答
協(xié)議實(shí)際上就是一種約定。好比說,我們做一個(gè)石頭剪刀布的游戲,我們約定好:石頭>剪刀、剪刀>布、布>石頭,以此作為游戲規(guī)則。我們所有人都遵循這個(gè)約定,那么就不需要任何的多余的溝通便可以完成這個(gè)游戲。而這種方式形成的約定實(shí)際上就是一種協(xié)議了。
話聯(lián)網(wǎng)早期是,盡管知道計(jì)算機(jī)連接的原理,但是沒有協(xié)議的時(shí)候,就沒有辦法進(jìn)行大規(guī)模的通信使用。當(dāng)時(shí)就衍生出了很多為了解決當(dāng)時(shí)問題的協(xié)議,像TCP協(xié)議就是為了約定大家使用TCP連接時(shí)傳輸?shù)囊环N協(xié)議,HTTP協(xié)議則是為了約定文本傳輸?shù)囊环N協(xié)議。
而TCP/IP協(xié)議并不是指某一個(gè)具體的協(xié)議,它是指代一系列的協(xié)議棧,因此也叫TCP/IP協(xié)議?;蛘逿CP/IP協(xié)議簇。
所以廣義上,我們說的TCP/IP指的是4層的總和。 而狹義上來說,指的是4層中的傳輸層和網(wǎng)絡(luò)互聯(lián)層。
在 TCP/IP協(xié)議簇 中,定義了包含對(duì)應(yīng) OSI 模型的每一層。但同時(shí)對(duì) OSI 模型層做了簡化處理??纯催@種圖理解一下:
TCP/IP層和OSI參考模型層的對(duì)應(yīng)關(guān)系
也即是OSI模型中的7層,在TCP/IP中使用4層代替了。沒辦法,誰讓OSI那么復(fù)雜呢。
在TCP/IP協(xié)議簇中每一層都有對(duì)應(yīng)的協(xié)議,最終組成協(xié)議簇。
TCP/IP協(xié)議棧每一層的協(xié)議
我們經(jīng)常說的TCP和UDP在協(xié)議棧的傳輸層,而IP協(xié)議則在協(xié)議棧的網(wǎng)絡(luò)互聯(lián)層。還有經(jīng)常被問到的HTTP協(xié)議實(shí)際上在協(xié)議棧的應(yīng)用層。
TCP/IP協(xié)議棧被分作這么多的層級(jí),目的是為了整理硬件間通信時(shí)的一個(gè)通用的模型,因此它們每一層都和其上下層有關(guān)聯(lián)性的,如下圖:
TCP/IP協(xié)議棧數(shù)據(jù)封包分層
上面就是'TCP/IP協(xié)議'的總體概念了。但是其內(nèi)部還有這么多的協(xié)議,這里挑幾個(gè)常見的講一講,從底層到上層:
IP協(xié)議
TCP協(xié)議
UDP協(xié)議
HTTP協(xié)議
IP協(xié)議處于TCP/IP協(xié)議簇的網(wǎng)絡(luò)互聯(lián)層。它提供不可靠、無連接的服務(wù),也即依賴其他層的協(xié)議進(jìn)行差錯(cuò)控制。在局域網(wǎng)環(huán)境,IP協(xié)議往往被封裝在以太網(wǎng)幀中傳送。而所有的TCP、UDP、ICMP、IGMP數(shù)據(jù)都被封裝在IP數(shù)據(jù)包包中傳送。
在IP協(xié)議中,有兩個(gè)重要的內(nèi)容需要了解下。一是IP地址的概念,二是IP協(xié)議的報(bào)頭。
其實(shí)對(duì)于IP地址我們?nèi)粘=佑|還是挺多的。它給每一個(gè)接入互聯(lián)網(wǎng)的計(jì)算器一個(gè)地址,從而使得其他的計(jì)算機(jī)能夠訪問到它。與此同時(shí),當(dāng)計(jì)算機(jī)有了地址之后,才能遵循IP協(xié)議,和其他的計(jì)算機(jī)進(jìn)行數(shù)據(jù)的傳遞。
目前有兩種IP版本,分別是IPV4和IPV6。IPV4占用8個(gè)字節(jié)32bit,而IPV6則是32個(gè)字節(jié)128bit。IPV6的可用的數(shù)量極其龐大,大到全球每一粒沙子都可以分配一個(gè)IPV6地址。
以IPV4為例, IPV4的32bit地址中,分為兩個(gè)部分:網(wǎng)絡(luò)號(hào)和主機(jī)號(hào)。同時(shí)根據(jù)不同的內(nèi)容開頭,又分為A、B、C、D、E類。
IPV4
網(wǎng)絡(luò)號(hào)用于區(qū)分不同的網(wǎng)絡(luò)點(diǎn),比如一個(gè)公司是一個(gè)網(wǎng)絡(luò)集群,我們可以通過他的網(wǎng)絡(luò)號(hào)確定該公司網(wǎng)關(guān),再通過主機(jī)號(hào)確定每一臺(tái)計(jì)算。
假如一個(gè)C類的IP地址類型,包含了21位網(wǎng)絡(luò)號(hào),實(shí)際上就能區(qū)分出 2^21 個(gè)網(wǎng)絡(luò)號(hào),而在每一個(gè)網(wǎng)絡(luò)號(hào)中,可以區(qū)分 2^8 -2 = 254(起始的網(wǎng)絡(luò)號(hào)地址和最后一個(gè)為廣播地址都不可用于主機(jī))個(gè)主機(jī)號(hào)。如果一個(gè)網(wǎng)吧采用這種方式的話,那么他最多能安裝254臺(tái)機(jī)器。如果我們想要得到更多的主機(jī)號(hào),應(yīng)該延長主機(jī)號(hào)的位數(shù),但是相應(yīng)的,網(wǎng)絡(luò)號(hào)的數(shù)量將減少,因?yàn)閮烧叩目傞L度是不變的。
通過掩碼能夠改變網(wǎng)絡(luò)號(hào)和主機(jī)號(hào)的位數(shù)。
通常,我們看到的掩碼類似:
255.255.255.0
二進(jìn)制表示:
11111111.11111111.11111111.00000000
如果一個(gè)IPV4地址為:192.168.1.12 那么IP地址和掩碼經(jīng)過與運(yùn)算之后的結(jié)果為:192.168.1.0(192.168.001.000), 這就是我們常說的網(wǎng)關(guān)! 而從 192.168.1.1~192.168.1.254都可作為主機(jī)號(hào)。也即是這個(gè)網(wǎng)關(guān)下,可以容納 254 臺(tái)機(jī)器。
如果將掩碼更改為:
255.255.254.0
二進(jìn)制表示:
11111111.11111111.11111110.00000000
那么與運(yùn)算的結(jié)果為:192.168.0.0 ,這時(shí)候可以使用的主機(jī)號(hào)就變成了 192.168.0.0 ~ 192.168.1.254, 即可容納 510 臺(tái)機(jī)器。
當(dāng)一個(gè) IP 包從一臺(tái)計(jì)算機(jī)被發(fā)送,它會(huì)到達(dá)一個(gè) IP 路由器。
IP 路由器負(fù)責(zé)將這個(gè)包路由至它的目的地,直接地或者通過其他的路由器。
在一個(gè)相同的通信中,一個(gè)包所經(jīng)由的路徑可能會(huì)和其他的包不同。而路由器負(fù)責(zé)根據(jù)通信量、網(wǎng)絡(luò)中的錯(cuò)誤或者其他參數(shù)來進(jìn)行正確地尋址。
在上面的數(shù)據(jù)分層中,我們看到IP協(xié)議的構(gòu)成實(shí)際上是 IP報(bào)頭 + TCP協(xié)議內(nèi)容。
因此決定一個(gè)IP協(xié)議屬性的的關(guān)鍵是 IP報(bào)頭的內(nèi)容。 下面我們來看下IP協(xié)議的組成,IPV4中普通的IP首部長20個(gè)字節(jié)。其中有32位的源IP地址和32位的目的IP地址。
TTL:生存時(shí)間。代表了數(shù)據(jù)包可以經(jīng)過的最多路由器數(shù)。比如TTL為10,意思是如果經(jīng)過10次路由器轉(zhuǎn)發(fā),仍然未找到目的地址,則報(bào)文丟棄
8位協(xié)議指示的是傳輸層承載的協(xié)議
16位總長度:指IP數(shù)據(jù)包的最大長度。16bit那么最長可達(dá)65535字節(jié)。但是通過鏈路的MTU不會(huì)有這么大。因此如果數(shù)據(jù)包長度超過了MTU,數(shù)據(jù)包會(huì)被分片。如果發(fā)生了分片,則需要用到16位標(biāo)識(shí)以及13位片偏移來找到分片的報(bào)文。
IP協(xié)議報(bào)頭
2.2 TCP協(xié)議
2.2.1 TCP協(xié)議作用
TCP協(xié)議位于協(xié)議棧的傳輸層。當(dāng)應(yīng)用層向TCP層發(fā)送用于網(wǎng)間傳輸?shù)摹⒂?位字節(jié)表示的數(shù)據(jù)流,TCP則把數(shù)據(jù)流分割成適當(dāng)長度的報(bào)文段,最大傳輸段大?。∕SS)通常受該計(jì)算機(jī)連接的網(wǎng)絡(luò)的數(shù)據(jù)鏈路層的最大傳送單元(MTU)限制。之后TCP把數(shù)據(jù)包傳給IP層,由它來通過網(wǎng)絡(luò)將包傳送給接收端實(shí)體的TCP層。
TCP為了保證報(bào)文傳輸?shù)目煽?,就給每個(gè)包一個(gè)序號(hào),同時(shí)序號(hào)也保證了傳送到接收端實(shí)體的包的按序接收。然后接收端實(shí)體對(duì)已成功收到的字節(jié)發(fā)回一個(gè)相應(yīng)的確認(rèn)(ACK);如果發(fā)送端實(shí)體在合理的往返時(shí)延(RTT)內(nèi)未收到確認(rèn),那么對(duì)應(yīng)的數(shù)據(jù)(假設(shè)丟失了)將會(huì)被重傳。
在數(shù)據(jù)正確性與合法性上,TCP用一個(gè)校驗(yàn)和函數(shù)來檢驗(yàn)數(shù)據(jù)是否有錯(cuò)誤,在發(fā)送和接收時(shí)都要計(jì)算校驗(yàn)和;同時(shí)可以使用md5認(rèn)證對(duì)數(shù)據(jù)進(jìn)行加密。
在保證可靠性上,采用超時(shí)重傳和捎帶確認(rèn)機(jī)制。
在流量控制上,采用滑動(dòng)窗口協(xié)議,協(xié)議中規(guī)定,對(duì)于窗口內(nèi)未經(jīng)確認(rèn)的分組需要重傳。
在擁塞控制上,采用廣受好評(píng)的TCP擁塞控制算法(也稱AIMD算法)。 該算法主要包括三個(gè)主要部分: (1)加性增、乘性減; (2)慢啟動(dòng); (3)對(duì)超時(shí)事件做出反應(yīng)。
和IP協(xié)議一樣,TCP協(xié)議也有他的報(bào)頭部分。
以下即是圖示:
TCP報(bào)頭
源端口:發(fā)送方的端口號(hào)
目的端口:接受方的端口號(hào)
序號(hào):發(fā)送方的序號(hào)
確認(rèn)序號(hào):接受方得到序號(hào)之后回復(fù)的確認(rèn)序號(hào)
TCP 首部長度:4 bits,以32-bit字為單位。TCP首部長短,也是TCP報(bào)文數(shù)據(jù)部分的偏移量。范圍5~15,即20 bytes ~ 60 bytes。可選項(xiàng)部分最多允許40 bytes。
標(biāo)志位,標(biāo)志位主要用戶標(biāo)志該報(bào)文當(dāng)前的狀態(tài)。
URG:指示報(bào)文中有緊急數(shù)據(jù),應(yīng)盡快傳送(相當(dāng)于高優(yōu)先級(jí)的數(shù)據(jù))。 ACK:確認(rèn)序號(hào)(AN)有效。 PSH:接到后盡快交付給接收的應(yīng)用進(jìn)程。 RST:TCP連接中出現(xiàn)嚴(yán)重差錯(cuò)(如主機(jī)崩潰),必須釋放連接,再重新建立連接。 SYN:處于TCP連接建立過程。 FIN:發(fā)送端已完成數(shù)據(jù)傳輸,請(qǐng)求釋放連接。
TCP是一個(gè)面向連接的協(xié)議,在每一次傳輸數(shù)據(jù)前,客戶端和服務(wù)端需要進(jìn)行連接,這個(gè)鏈接就是著名的三次握手。
第一次:客戶端向服務(wù)端發(fā)送一個(gè) SYN(SEQ=x 客戶端序號(hào))報(bào)文給服務(wù)器端,進(jìn)入SYN_SEND狀態(tài)。
第二次:服務(wù)器端收到SYN報(bào)文,回應(yīng)一個(gè)SYN (SEQ=y 服務(wù)端序號(hào))ACK(ACK=x+1 確認(rèn)號(hào)=客戶端序號(hào)+1)報(bào)文,進(jìn)入SYN_RECV狀態(tài)。
第三次:客戶端收到服務(wù)器端的SYN報(bào)文,回應(yīng)一個(gè)ACK(ACK=y+1)報(bào)文,進(jìn)入Established狀態(tài)。
圖解:
TCP的三次握手
思考:為什么要進(jìn)行三次握手,而不是兩次呢? 比如在第一次握手之后,服務(wù)器進(jìn)入準(zhǔn)備狀態(tài),然后發(fā)送消息給客戶端,客戶端也進(jìn)入準(zhǔn)備狀態(tài),這就完成了雙方的確認(rèn)了。
回答:兩次握手時(shí),服務(wù)器提前進(jìn)入準(zhǔn)備狀態(tài)之后,如果中途遇到網(wǎng)絡(luò)中斷,消息并沒有傳回給客戶端,客戶端將永遠(yuǎn)接不到服務(wù)器的給入狀態(tài),那么服務(wù)端將資源浪費(fèi)在一個(gè)不存在的連接之上了。
思考2:三次握手就很安全了嗎?
回答:在三次握手過程中,Server發(fā)送SYN-ACK之后,收到Client的ACK之前的TCP連接稱為半連接(half-open connect),此時(shí)Server處于SYN_RCVD狀態(tài),當(dāng)收到ACK后,Server轉(zhuǎn)入ESTABLISHED狀態(tài)。SYN攻擊就是Client在短時(shí)間內(nèi)偽造大量不存在的IP地址,并向Server不斷地發(fā)送SYN包,Server回復(fù)確認(rèn)包,并等待Client的確認(rèn),由于源地址是不存在的,因此,Server需要不斷重發(fā)直至超時(shí),這些偽造的SYN包將長時(shí)間占用未連接隊(duì)列,導(dǎo)致正常的SYN請(qǐng)求因?yàn)殛?duì)列滿而被丟棄,從而引起網(wǎng)絡(luò)堵塞甚至系統(tǒng)癱瘓。SYN攻擊是一種典型的DDOS攻擊,檢測SYN攻擊的方式非常簡單,即當(dāng)Server上有大量半連接狀態(tài)且源IP地址是隨機(jī)的,則可以斷定遭到SYN攻擊了,使用如下命令可以讓之現(xiàn)行:
#netstat -nap | grep SYN_RECV
既然TCP面向連接,那么肯定也有斷開連接的操作。一個(gè)TCP完整的斷開需要進(jìn)行四次揮手。
第一次:客戶端向服務(wù)端發(fā)送 FIN + ACK 報(bào)文,同時(shí)攜帶序號(hào)為 X。 客戶端進(jìn)入 FIN-WAIT1
第二次:服務(wù)器端回復(fù) ACK 報(bào)文。附帶序號(hào)Z和確認(rèn)序號(hào)X+1,表示服務(wù)器已經(jīng)接受到了客服端的報(bào)文。但是由于服務(wù)器可能還在處理事務(wù),因此,報(bào)文并不會(huì)攜帶FIN標(biāo)志。狀態(tài):CLOSE WAIT
第三次:在一段時(shí)間之后,服務(wù)器已經(jīng)處理完畢,發(fā)送帶有 FIN和ACK的報(bào)文,序號(hào)為Y,確認(rèn)序號(hào)為 X + 1 。 狀態(tài): ACK-LAST
第四次:客戶端發(fā)送ACK報(bào)文,序號(hào)為 X+1,確認(rèn)號(hào)Y+1 。 客戶端進(jìn)入: TIME_WAIT。服務(wù)端進(jìn)圖CLOSE(初始狀態(tài))
TCP四次揮手
思考:為什么建立連接是三次握手,而關(guān)閉連接卻是四次揮手呢?
回答:這是因?yàn)榉?wù)端在LISTEN狀態(tài)下,收到建立連接請(qǐng)求的SYN報(bào)文后,把ACK和SYN放在一個(gè)報(bào)文里發(fā)送給客戶端。而關(guān)閉連接時(shí),當(dāng)收到對(duì)方的FIN報(bào)文時(shí),僅僅表示對(duì)方不再發(fā)送數(shù)據(jù)了但是還能接收數(shù)據(jù),己方也未必全部數(shù)據(jù)都發(fā)送給對(duì)方了,所以己方可以立即close,也可以發(fā)送一些數(shù)據(jù)給對(duì)方后,再發(fā)送FIN報(bào)文給對(duì)方來表示同意現(xiàn)在關(guān)閉連接,因此,己方ACK和FIN一般都會(huì)分開發(fā)送。
思考:為什么TIME_WAIT狀態(tài)需要經(jīng)過2MSL(最大報(bào)文段生存時(shí)間)才能返回到CLOSE狀態(tài)?
原因有二:
一、保證TCP協(xié)議的全雙工連接能夠可靠關(guān)閉
二、保證這次連接的重復(fù)數(shù)據(jù)段從網(wǎng)絡(luò)中消失
UDP協(xié)議全稱是用戶數(shù)據(jù)包協(xié)議,在網(wǎng)絡(luò)中它與TCP協(xié)議一樣用于處理數(shù)據(jù)包,兩者同處于協(xié)議棧的傳輸層,和TCP不同的是,UDP是一種無連接的協(xié)議。
因?yàn)閁DP是無連接的,所以相對(duì)來說,UDP的報(bào)頭比TCP要簡單多了。
UDP報(bào)頭
UDP 特點(diǎn) (1) UDP是一個(gè)非連接的協(xié)議,傳輸數(shù)據(jù)之前源端和終端不建立連接,當(dāng)它想傳送時(shí)就簡單地去抓取來自應(yīng)用程序的數(shù)據(jù),并盡可能快地把它扔到網(wǎng)絡(luò)上。在發(fā)送端,UDP傳送數(shù)據(jù)的速度僅僅是受應(yīng)用程序生成數(shù)據(jù)的速度、計(jì)算機(jī)的能力和傳輸帶寬的限制;在接收端,UDP把每個(gè)消息段放在隊(duì)列中,應(yīng)用程序每次從隊(duì)列中讀一個(gè)消息段。 (2) 由于傳輸數(shù)據(jù)不建立連接,因此也就不需要維護(hù)連接狀態(tài),包括收發(fā)狀態(tài)等,因此一臺(tái)服務(wù)機(jī)可同時(shí)向多個(gè)客戶機(jī)傳輸相同的消息。 (3) UDP信息包的標(biāo)題很短,只有8個(gè)字節(jié),相對(duì)于TCP的20個(gè)字節(jié)信息包的額外開銷很小。 (4) 吞吐量不受擁擠控制算法的調(diào)節(jié),只受應(yīng)用軟件生成數(shù)據(jù)的速率、傳輸帶寬、源端和終端主機(jī)性能的限制。 (5)UDP使用盡最大努力交付,即不保證可靠交付,因此主機(jī)不需要維持復(fù)雜的鏈接狀態(tài)表(這里面有許多參數(shù))。 (6)UDP是面向報(bào)文的。發(fā)送方的UDP對(duì)應(yīng)用程序交下來的報(bào)文,在添加首部后就向下交付給IP層。既不拆分,也不合并,而是保留這些報(bào)文的邊界,因此,應(yīng)用程序需要選擇合適的報(bào)文大小。
我們經(jīng)常使用“ping”命令來測試兩臺(tái)主機(jī)之間TCP/IP通信是否正常,其實(shí)“ping”命令的原理就是向?qū)Ψ街鳈C(jī)發(fā)送UDP數(shù)據(jù)包,然后對(duì)方主機(jī)確認(rèn)收到數(shù)據(jù)包,如果數(shù)據(jù)包是否到達(dá)的消息及時(shí)反饋回來,那么網(wǎng)絡(luò)就是通的。
2.4 HTTP協(xié)議
HTTP協(xié)議名為超文本傳輸協(xié)議。這個(gè)協(xié)議在 TCP/IP 協(xié)議棧的應(yīng)用層,因此我們無需操心HTTP是如何傳輸?shù)?,只需要關(guān)心,我們傳輸?shù)膬?nèi)容,能否正確的被接收端識(shí)別。
HTTP 基于TCP實(shí)現(xiàn),簡單來說,TCP協(xié)議負(fù)責(zé)可靠的內(nèi)容傳輸,HTTP協(xié)議負(fù)責(zé)識(shí)別內(nèi)容,兩者本身不在一個(gè)層面,沒有可比性。
HTTP無狀態(tài)的意思是,每一次的內(nèi)容解析是沒有關(guān)聯(lián)的。TCP有狀態(tài)是指兩端在連接過程的。
HTTP包含兩種報(bào)文類型:請(qǐng)求報(bào)文、響應(yīng)報(bào)文。請(qǐng)求報(bào)文用在客戶端對(duì)服務(wù)器的請(qǐng)求時(shí)使用的報(bào)文格式,響應(yīng)用在服務(wù)器響應(yīng)請(qǐng)求的報(bào)文格式。
2.4.1 HTTP協(xié)議請(qǐng)求消息結(jié)構(gòu)
客戶端發(fā)送一個(gè)HTTP請(qǐng)求到服務(wù)器的請(qǐng)求消息包括以下格式:請(qǐng)求行(request line)、請(qǐng)求頭部(header)、空行和請(qǐng)求數(shù)據(jù)四個(gè)部分組成,下圖給出了請(qǐng)求報(bào)文的一般格式。
HTTP請(qǐng)求消息體結(jié)構(gòu)
HTTP消息體主要包含以下實(shí)質(zhì)內(nèi)容(空格和換行也必不可少):
請(qǐng)求方法 URL:統(tǒng)一資源定位符 HTTP請(qǐng)求頭部 HTTP請(qǐng)求體
以下是一個(gè)HTTP請(qǐng)求的例子:
HTTP請(qǐng)求實(shí)例
2.4.1.1 HTTP請(qǐng)求方法
HTTP包含了多種不同的請(qǐng)求方式,每一種請(qǐng)求方式用在不同的場景。
HTTP請(qǐng)求方法
2.4.1.2 URL —— 統(tǒng)一資源定位符
URL由三部分組成:資源類型、存放資源的主機(jī)域名、資源文件名。
URL的一般語法格式為:
(帶方括號(hào)[]的為可選項(xiàng)):
protocol :// hostname[:port] / path / [;parameters][?query]#fragment
protocol:https
hostname:baijiahao.baidu.com
parameters:id=1603848351636567407&wfr=spider&for=pc (使用&分割參數(shù))
總結(jié)一下如下圖:
附一張解析圖
2.4.1.3 HTTP請(qǐng)求頭
請(qǐng)求頭中主要包含本次請(qǐng)求的附加信息,其中常用的字段如:
Accept: 指定客戶端能夠接收的內(nèi)容類型
Accept-Encoding: 指定瀏覽器可以支持的web服務(wù)器返回內(nèi)容壓縮編碼類型。
Accept-Language: 瀏覽器可接受的語言
Content-Length 請(qǐng)求的內(nèi)容長度 如:Content-Length: 348
Content-Type 請(qǐng)求的與實(shí)體對(duì)應(yīng)的MIME信息,常用的類型
Date 請(qǐng)求發(fā)送的日期和時(shí)間
更多的請(qǐng)求頭字段參考 HTTP響應(yīng)頭和請(qǐng)求頭信息對(duì)照表
2.4.1.4 HTTP請(qǐng)求體
在整個(gè)報(bào)文中,請(qǐng)求頭之后,隔一行空格,以下部分就是HTTP的請(qǐng)求體了。 請(qǐng)求體是我們發(fā)送請(qǐng)求的時(shí)候需要傳給接收端的內(nèi)容。其格式需要和請(qǐng)求頭中的Content-Type對(duì)應(yīng)。不然會(huì)導(dǎo)致接受無法識(shí)別。
如上圖中的請(qǐng)求題: name=tom&password=1234
2.4.2 HTTP響應(yīng)
HTTP的響應(yīng)同樣分為:響應(yīng)行、響應(yīng)頭、響應(yīng)體。和請(qǐng)求報(bào)文有點(diǎn)類似。
總體結(jié)構(gòu)如圖:
HTTP響應(yīng)報(bào)文
2.4.2.1 HTTP響應(yīng)行
響應(yīng)行中包含了HTTP的版本和本次請(qǐng)求的狀態(tài)。請(qǐng)求狀態(tài)的對(duì)應(yīng)值見 HTTP響應(yīng)碼大全.
響應(yīng)頭用于描述服務(wù)器的基本信信息、數(shù)據(jù)的描述,這些信息將告知客戶端如何處理響應(yīng)題中的內(nèi)容。
Allow 服務(wù)器支持哪些請(qǐng)求方法(如GET、POST等)。
Content-Encoding 文檔的編碼(Encode)方法。只有在解碼之后才可以得到Content-Type頭指定的內(nèi)容類型。利用gzip壓縮文檔能夠顯著地減少HTML文檔的下載時(shí)間。Java的GZIPOutputStream可以很方便地進(jìn)行g(shù)zip壓縮,但只有Unix上的Netscape和Windows上的IE 4、IE 5才支持它。因此,Servlet應(yīng)該通過查看Accept-Encoding頭(即request.getHeader('Accept-Encoding'))檢查瀏覽器是否支持gzip,為支持gzip的瀏覽器返回經(jīng)gzip壓縮的HTML頁面,為其他瀏覽器返回普通頁面。
Content-Length 表示內(nèi)容長度。只有當(dāng)瀏覽器使用持久HTTP連接時(shí)才需要這個(gè)數(shù)據(jù)。如果你想要利用持久連接的優(yōu)勢,可以把輸出文檔寫入 ByteArrayOutputStream,完成后查看其大小,然后把該值放入Content-Length頭,最后通過byteArrayStream.writeTo(response.getOutputStream()發(fā)送內(nèi)容。
Content-Type 表示后面的文檔屬于什么MIME類型。Servlet默認(rèn)為text/plain,但通常需要顯式地指定為text/html。由于經(jīng)常要設(shè)置Content-Type,因此HttpServletResponse提供了一個(gè)專用的方法setContentType。
2.4.2.3 HTTP響應(yīng)實(shí)體
響應(yīng)實(shí)體中包含的就是客戶端從服務(wù)器中獲取的數(shù)據(jù)了。數(shù)據(jù)的格式和長度都會(huì)在響應(yīng)體頭中描述。
聯(lián)系客服