一、簡介
TCP、UDP、HTTP、HTTPS 都是通信協(xié)議,也就是通信時所遵守的規(guī)則,只有雙方按照這個規(guī)則“說話”,對方才能理解或為之服務(wù)。
二、TCP、UDP、HTTP、HTTPS 之間的關(guān)系
TCP/IP 是個協(xié)議組,可分為四個層次:網(wǎng)絡(luò)接口層、網(wǎng)絡(luò)層、傳輸層和應(yīng)用層。
在網(wǎng)絡(luò)層,有 IP 協(xié)議、ICMP 協(xié)議、ARP 協(xié)議、RARP 協(xié)議等。
在傳輸層,有 TCP 協(xié)議與 UDP 協(xié)議。
在應(yīng)用層,有 WebSocket、FTP、HTTP、TELNET、SMTP、DNS 等協(xié)議。
而 HTTPS 可以理解為更安全的 HTTP 協(xié)議。
因此,TCP、UDP、HTTP、HTTPS 都是通信協(xié)議,只不過它們所在的層級不同,負(fù)責(zé)的工作也不同,并且 HTTP 是基于 TCP 實現(xiàn)的。
三、Socket 通信
Socket 是為了實現(xiàn)以上的通信過程而建立成來的通信管道,其真實的代表是客戶端和服務(wù)器端的一個通信進(jìn)程,雙方進(jìn)程通過 Socket 進(jìn)行通信,而通信的規(guī)則采用指定的協(xié)議。Socket 只是一種連接模式,不是協(xié)議。TCP、UDP,簡單的說(雖然不準(zhǔn)確)是兩個基本的協(xié)議,很多其它協(xié)議都是基于這兩個協(xié)議,如 HTTP 就是基于 TCP 的。用 Socket 可以創(chuàng)建 TCP 連接,也可以創(chuàng)建 UDP 連接,這意味著,用 Socket 可以創(chuàng)建任何協(xié)議的連接,因為其它協(xié)議都是基于此的。
四、TCP 協(xié)議
TCP 的建立連接協(xié)議又稱之為“三次握手”:
第一次握手:建立連接時,客戶端發(fā)送 SYN 包(syn=i)到服務(wù)器,并進(jìn)入 SYN_SEND 狀態(tài),等待服務(wù)器確認(rèn)。
第二次握手:服務(wù)器收到客戶端發(fā)來的 SYN 包,必須對客戶端進(jìn)行確認(rèn) ACK (ack=i+1),同時服務(wù)器也發(fā)送一個 SYN 包(syn=j)到客戶端,即服務(wù)器會發(fā)送 SYN+ACK 包,此時服務(wù)器進(jìn)入 SYN_RECV 狀態(tài)。
第三次握手:客戶端收到服務(wù)器發(fā)送的 SYN+ACK 包,向服務(wù)器發(fā)送確認(rèn)包 ACK(ack=j+1),此包發(fā)送完畢,客戶端和服務(wù)器進(jìn)入 ESTABLISHED 狀態(tài),完成三次握手。

為什么需要“三次握手”
第一個原因:初始化 Seq,TCP 通信是有序的,通信雙方要通知對方自己的 Seq 值,也就是上圖中的 X 和 Y,這個值要作為之后數(shù)據(jù)通信的序號,以保證應(yīng)用層接受到數(shù)據(jù)不會因網(wǎng)絡(luò)延時等原因而亂序,TCP 會用 Seq 來拼接數(shù)據(jù)。
第二個原因:在謝希仁版《計算機(jī)網(wǎng)絡(luò)》第四版中講“三次握手”的目的是“為了防止已失效的連接請求報文段突然又傳送到了服務(wù)端,因而產(chǎn)生錯誤”。在另一部經(jīng)典的《計算機(jī)網(wǎng)絡(luò)》一書中講“三次握手”的目的是為了解決“網(wǎng)絡(luò)中存在延遲的重復(fù)分組”的問題。這兩種不同的表述其實闡明的是同一個問題。
謝希仁版《計算機(jī)網(wǎng)絡(luò)》中的例子是這樣的,“已失效的連接請求報文段”的產(chǎn)生在這樣一種情況下:Client 發(fā)出的第一個連接請求報文段并沒有丟失,而是在某個網(wǎng)絡(luò)結(jié)點長時間的滯留了,以致延誤到連接釋放以后的某個時間才到達(dá) Server。本來這是一個早已失效的報文段。但 Server 收到此失效的連接請求報文段后,就誤認(rèn)為是 Client 再次發(fā)出的一個新的連接請求。于是就向 Client 發(fā)出確認(rèn)報文段,同意建立連接。
假設(shè)不采用“三次握手”,那么只要 Server 發(fā)出確認(rèn),新的連接就建立了。由于現(xiàn)在 Client 并沒有發(fā)出建立連接的請求,因此不會理睬 Server 的確認(rèn),也不會向 Server 發(fā)送數(shù)據(jù)。但 Server 卻以為新的運輸連接已經(jīng)建立,并一直等待 Client 發(fā)來數(shù)據(jù)。這樣,Server 的很多資源就白白浪費掉了。
“四次揮手”過程
由于 TCP 連接是全雙工的,因此每個方向都必須單獨進(jìn)行關(guān)閉。這原則是當(dāng)一方完成它的數(shù)據(jù)發(fā)送任務(wù)后就能發(fā)送一個 FIN 來終止這個方向的連接。收到一個 FIN 只意味著這一方向上沒有數(shù)據(jù)流動,而對方仍能發(fā)送數(shù)據(jù)。首先進(jìn)行關(guān)閉的一方將執(zhí)行主動關(guān)閉,而另一方執(zhí)行被動關(guān)閉。
- TCP 客戶端發(fā)送一個 FIN,用來關(guān)閉客戶到服務(wù)器的數(shù)據(jù)傳送。
- 服務(wù)器收到這個 FIN,發(fā)回一個 ACK,確認(rèn)序號為收到的序號加 1。和 SYN 一樣,一個 FIN 將占用一個序號。
- 服務(wù)器關(guān)閉客戶端的連接,發(fā)送一個 FIN 給客戶端。
- 客戶段發(fā)回 ACK 報文確認(rèn),并將確認(rèn)序號設(shè)置為收到序號加1。

為什么需要“四次揮手”
那可能有人會有疑問,在 TCP 連接握手時為何 ACK 是和 SYN 一起發(fā)送,這里 ACK 卻沒有和 FIN 一起發(fā)送呢?
原因是因為 TCP 是全雙工模式,接收到 FIN 時意味將沒有數(shù)據(jù)再發(fā)來,但是還是可以繼續(xù)發(fā)送數(shù)據(jù)。同時發(fā)送雙方都需要發(fā)送 FIN 報文和 ACK 報文,加起來就是四次了。
TIME_WAIT 狀態(tài)
在四次揮手的最后一次揮手中,主動斷開方在發(fā)送最后一個 ACK 后,不能立刻關(guān)閉,而是需要等待 2MSL 后才能關(guān)閉,這是為什么呢?同時這也是面試中常提到的一個問題。原因如下:
假設(shè)發(fā)起主動關(guān)閉的一方(Client)最后發(fā)送的 ACK 在網(wǎng)絡(luò)中丟失,由于 TCP 協(xié)議的重傳機(jī)制,被動關(guān)閉的一方將會重發(fā) FIN,在該 FIN 到達(dá) Client之前,Client 必須維護(hù)這條連接狀態(tài),也就說這條 TCP 連接所對應(yīng)的資源不能被立即釋放或重新分配,直到另一方重發(fā)的 FIN 達(dá)到之后,Client 重發(fā) ACK 后,經(jīng)過 2MSL 時間周期沒有再收到另一方的 FIN 之后,該 TCP 連接才能 CLOSED。
如果主動關(guān)閉一方不維護(hù)這樣一個 TIME_WAIT 狀態(tài),那么當(dāng)被動關(guān)閉一方重發(fā)的 FIN 到達(dá)時,主動關(guān)閉一方的 TCP 傳輸層會用 RST 包響應(yīng)對方,這會被對方認(rèn)為是有錯誤發(fā)生,然而這事實上只是正常的關(guān)閉連接過程,并非異常。
TCP 粘包拆包
TCP是基于字節(jié)流的,雖然應(yīng)用層和 TCP 傳輸層之間的數(shù)據(jù)交互是大小不等的數(shù)據(jù)塊,但是 TCP 把這些數(shù)據(jù)塊僅僅看成一連串無結(jié)構(gòu)的字節(jié)流,沒有邊界;另外從 TCP 的幀結(jié)構(gòu)也可以看出,在 TCP 的首部沒有表示數(shù)據(jù)長度的字段,基于上面兩點,在使用TCP傳輸數(shù)據(jù)時,才有粘包或者拆包現(xiàn)象發(fā)生的可能。
粘包、拆包發(fā)生原因
發(fā)生TCP粘包或拆包有很多原因,現(xiàn)列出常見的幾點:
- 要發(fā)送的數(shù)據(jù)大于TCP發(fā)送緩沖區(qū)剩余空間大小,將會發(fā)生拆包。
- 待發(fā)送數(shù)據(jù)大于MSS(最大報文長度),TCP在傳輸前將進(jìn)行拆包。
- 要發(fā)送的數(shù)據(jù)小于TCP發(fā)送緩沖區(qū)的大小,TCP將多次寫入緩沖區(qū)的數(shù)據(jù)一次發(fā)送出去,將會發(fā)生粘包。
- 接收數(shù)據(jù)端的應(yīng)用層沒有及時讀取接收緩沖區(qū)中的數(shù)據(jù),將發(fā)生粘包。

粘包、拆包解決辦法
通過以上分析,我們清楚了粘包或拆包發(fā)生的原因,那么如何解決這個問題呢?解決問題的關(guān)鍵在于如何給每個數(shù)據(jù)包添加邊界信息,常用的方法有如下幾個:
1、發(fā)送端給每個數(shù)據(jù)包添加包首部,首部中應(yīng)該至少包含數(shù)據(jù)包的長度,這樣接收端在接收到數(shù)據(jù)后,通過讀取包首部的長度字段,便知道每一個數(shù)據(jù)包的實際長度了。
2、發(fā)送端將每個數(shù)據(jù)包封裝為固定長度(不夠的可以通過補0填充),這樣接收端每次從接收緩沖區(qū)中讀取固定長度的數(shù)據(jù)就自然而然的把每個數(shù)據(jù)包拆分開來。
3、可以在數(shù)據(jù)包之間設(shè)置邊界,如添加特殊符號,這樣,接收端通過這個邊界就可以將不同的數(shù)據(jù)包拆分開。
那么 UDP 是否會發(fā)生粘包或拆包的現(xiàn)象呢?
答案是:不會。UDP 是基于報文發(fā)送的,從 UDP 的幀結(jié)構(gòu)可以看出,在 UDP 首部采用了 16bit 來指示 UDP 數(shù)據(jù)報文的長度,因此在應(yīng)用層能很好的將不同的數(shù)據(jù)報文區(qū)分開,從而避免粘包和拆包的問題。
五、什么是HTTP協(xié)議
HTTP 全稱是 HyperText Transfer Protocal,即:超文本傳輸協(xié)議。從1990 年開始就在 WWW 上廣泛應(yīng)用,是現(xiàn)今在 WWW 上應(yīng)用最多的協(xié)議。HTTP 是應(yīng)用層協(xié)議,當(dāng)你上網(wǎng)瀏覽網(wǎng)頁的時候,瀏覽器和 Web 服務(wù)器之間就會通過 HTTP 在 Internet 上進(jìn)行數(shù)據(jù)的發(fā)送和接收。HTTP 是一個基于請求/響應(yīng)模式的、無狀態(tài)的協(xié)議,即我們通常所說的 Request/Response。
先看看請求(Request)報文:

請求(Request)報文 = 請求行 + 請求頭 + 空行 + 請求體
請求行中包含請求方法,常見的請求方法有:
GET:獲取資源,當(dāng)前網(wǎng)絡(luò)請求中,絕大部分使用的是 GET 方法。
POST:傳輸實體主體,POST 主要用來傳輸數(shù)據(jù),而 GET 主要用來獲取資源。
PUT:上傳文件,由于自身不帶驗證機(jī)制,任何人都可以上傳文件,因此存在安全性問題,一般不使用該方法。
DELETE:刪除文件,與 PUT 功能相反,并且同樣不帶驗證機(jī)制。
HEAD:獲取報文首部,和 GET 方法類似,但是不返回報文實體主體部分。主要用于確認(rèn) URL 的有效性以及資源更新的日期時間等。

響應(yīng)(Response)報文 = 狀態(tài)行 + 響應(yīng)頭 + 空行 + 響應(yīng)體
其中,狀態(tài)行包含響應(yīng)的狀態(tài),常見的狀態(tài)如下:
1XX 信息
- 100 Continue :表明到目前為止都很正常,客戶端可以繼續(xù)發(fā)送請求或者忽略這個響應(yīng)。
2XX 成功
200 OK
204 No Content :請求已經(jīng)成功處理,但是返回的響應(yīng)報文不包含實體的主體部分。一般在只需要從客戶端往服務(wù)器發(fā)送信息,而不需要返回數(shù)據(jù)時使用。
206 Partial Content :表示客戶端進(jìn)行了范圍請求,響應(yīng)報文包含由 Content-Range 指定范圍的實體內(nèi)容。
3XX 重定向
301 Moved Permanently :永久性重定向
302 Found :臨時性重定向
303 See Other :和 302 有著相同的功能,但是 303 明確要求客戶端應(yīng)該采用 GET 方法獲取資源。
注:雖然 HTTP 協(xié)議規(guī)定 301、302 狀態(tài)下重定向時不允許把 POST 方法改成 GET 方法,但是大多數(shù)瀏覽器都會在 301、302 和 303 狀態(tài)下的重定向把 POST 方法改成 GET 方法。
304 Not Modified :如果請求報文首部包含一些條件,例如:If-Match,If-Modified-Since,If-None-Match,If-Range,If-Unmodified-Since,如果不滿足條件,則服務(wù)器會返回 304 狀態(tài)碼。
307 Temporary Redirect :臨時重定向,與 302 的含義類似,但是 307 要求瀏覽器不會把重定向請求的 POST 方法改成 GET 方法。
4XX 客戶端錯誤
400 Bad Request :請求報文中存在語法錯誤。
401 Unauthorized :該狀態(tài)碼表示發(fā)送的請求需要有認(rèn)證信息(BASIC 認(rèn)證、DIGEST 認(rèn)證)。如果之前已進(jìn)行過一次請求,則表示用戶認(rèn)證失敗。
403 Forbidden :請求被拒絕。
404 Not Found
5XX 服務(wù)器錯誤
500 Internal Server Error :服務(wù)器正在執(zhí)行請求時發(fā)生錯誤。
503 Service Unavailable :服務(wù)器暫時處于超負(fù)載或正在進(jìn)行停機(jī)維護(hù),現(xiàn)在無法處理請求。
HTTP 通信機(jī)制是在一次完整的 HTTP 通信過程中,Web 瀏覽器與 Web 服務(wù)器之間將完成下列7個步驟:
- 建立 TCP 連接
在 HTTP 工作開始之前,Web 瀏覽器首先要通過網(wǎng)絡(luò)與 Web 服務(wù)器建立連接,該連接是通過 TCP 來完成的,該協(xié)議與 IP 協(xié)議共同構(gòu)建 Internet,即著名的 TCP/IP 協(xié)議族,因此 Internet 又被稱作是 TCP/IP 網(wǎng)絡(luò)。HTTP 是比 TCP 更高層次的應(yīng)用層協(xié)議,根據(jù)規(guī)則,只有低層協(xié)議建立之后才能,才能進(jìn)行更層協(xié)議的連接,因此,首先要建立 TCP 連接,一般 TCP 連接的端口號是 80 - Web 瀏覽器向 Web 服務(wù)器發(fā)送請求命令
一旦建立了TCP連接,Web瀏覽器就會向Web服務(wù)器發(fā)送請求命令。例如:GET/sample/hello.jsp HTTP/1.1。 - Web 瀏覽器發(fā)送請求頭信息
瀏覽器發(fā)送其請求命令之后,還要以頭信息的形式向 Web 服務(wù)器發(fā)送一些別的信息,之后瀏覽器發(fā)送了一空白行來通知服務(wù)器,它已經(jīng)結(jié)束了該頭信息的發(fā)送。 - Web 服務(wù)器應(yīng)答
客戶機(jī)向服務(wù)器發(fā)出請求后,服務(wù)器會客戶機(jī)回送應(yīng)答,HTTP/1.1 200 OK,應(yīng)答的第一部分是協(xié)議的版本號和應(yīng)答狀態(tài)碼 - Web 服務(wù)器發(fā)送應(yīng)答頭信息
正如客戶端會隨同請求發(fā)送關(guān)于自身的信息一樣,服務(wù)器也會隨同應(yīng)答向用戶發(fā)送關(guān)于它自己的數(shù)據(jù)及被請求的文檔。 - Web 服務(wù)器向瀏覽器發(fā)送數(shù)據(jù)
Web 服務(wù)器向瀏覽器發(fā)送頭信息后,它會發(fā)送一個空白行來表示頭信息的發(fā)送到此為結(jié)束,接著,它就以Content-Type應(yīng)答頭信息所描述的格式發(fā)送用戶所請求的實際數(shù)據(jù) - Web 服務(wù)器關(guān)閉 TCP 連接
一般情況下,一旦 Web 服務(wù)器向瀏覽器發(fā)送了請求數(shù)據(jù),它就要關(guān)閉 TCP 連接,然后如果瀏覽器或者服務(wù)器在其頭信息加入了這行Connection:keep-alive,TCP 連接在發(fā)送后將仍然保持打開狀態(tài),于是,瀏覽器可以繼續(xù)通過相同的連接發(fā)送請求。保持連接節(jié)省了為每個請求建立新連接所需的時間,還節(jié)約了網(wǎng)絡(luò)帶寬。
六、HTTPS 的工作原理
HTTPS 在傳輸數(shù)據(jù)之前需要客戶端(瀏覽器)與服務(wù)端(網(wǎng)站)之間進(jìn)行一次握手,在握手過程中將確立雙方加密傳輸數(shù)據(jù)的密碼信息。TLS/SSL 協(xié)議不僅僅是一套加密傳輸?shù)膮f(xié)議,更是一件經(jīng)過藝術(shù)家精心設(shè)計的藝術(shù)品,TLS/SSL 中使用了非對稱加密、對稱加密以及 HASH 算法。握手過程的具體描述如下:
- 瀏覽器將自己支持的一套加密規(guī)則發(fā)送給網(wǎng)站。
- 網(wǎng)站從中選出一組加密算法與 HASH 算法,并將自己的身份信息以證書的形式發(fā)回給瀏覽器。證書里面包含了網(wǎng)站地址,加密公鑰,以及證書的頒發(fā)機(jī)構(gòu)等信息。
- 瀏覽器獲得網(wǎng)站證書之后瀏覽器要做以下工作:
a) 驗證證書的合法性(頒發(fā)證書的機(jī)構(gòu)是否合法,證書中包含的網(wǎng)站地址是否與正在訪問的地址一致等),如果證書受信任,則瀏覽器欄里面會顯示一個小鎖頭,否則會給出證書不受信的提示。
b) 如果證書受信任,或者是用戶接受了不受信的證書,瀏覽器會生成一串隨機(jī)數(shù)的密碼,并用證書中提供的公鑰加密。
c) 使用約定好的 HASH 算法計算握手消息,并使用生成的隨機(jī)數(shù)對消息進(jìn)行加密,最后將之前生成的所有信息發(fā)送給網(wǎng)站。 - 網(wǎng)站接收瀏覽器發(fā)來的數(shù)據(jù)之后要做以下的操作:
a) 使用自己的私鑰將信息解密取出密碼,使用密碼解密瀏覽器發(fā)來的握手消息,并驗證 HASH 是否與瀏覽器發(fā)來的一致。
b) 使用密碼加密一段握手消息,發(fā)送給瀏覽器。 - 瀏覽器解密并計算握手消息的 HASH,如果與服務(wù)端發(fā)來的 HASH 一致,此時握手過程結(jié)束,之后所有的通信數(shù)據(jù)將由之前瀏覽器生成的隨機(jī)密碼并利用對稱加密算法進(jìn)行加密。

簡單的說:HTTPS 使用對稱加密的方法通信,秘鑰為 Key。但是為了安全的把秘鑰 Key 發(fā)送給對方,于是在通信前,使用非對稱加密的方法加密 Key。
這樣做的目的是:非對稱加密的安全性更強,但是加解密過程復(fù)雜耗時,對稱加密的加解密過程簡單,但安全性不強,于是 HTTPS 綜合兩種加密方式,既保證了安全性,又保證了效率。
HTTPS協(xié)議和HTTP協(xié)議的區(qū)別:
- HTTPS 協(xié)議需要到 ca 申請證書,一般免費證書很少,需要交費。
- HTTP 是超文本傳輸協(xié)議,信息是明文傳輸,HTTPS 則是具有安全性的 SSL 加密傳輸協(xié)議。
- HTTP和HTTPS使用的是完全不同的連接方式用的端口也不一樣,前者是 80,后者是 443。
- HTTP 的連接很簡單,是無狀態(tài)的 。
- HTTPS 協(xié)議是由 SSL+HTTP 協(xié)議構(gòu)建的可進(jìn)行加密傳輸、身份認(rèn)證的網(wǎng)絡(luò)協(xié)議,要比 HTTP 協(xié)議安全。