享學(xué)課堂作者:逐夢々少年
轉(zhuǎn)載請聲明出處!
現(xiàn)代互聯(lián)網(wǎng)開發(fā)過程中,無論是什么架構(gòu)系統(tǒng),無法避免的并且很重要的一個環(huán)節(jié)就是網(wǎng)絡(luò)通訊,好的網(wǎng)絡(luò)通訊方案和協(xié)議會讓整個程序效率和耗時變得更低,而JAVA開發(fā)過程中我們一般接觸到的都是基于TCP/IP的網(wǎng)絡(luò)協(xié)議,所以一個優(yōu)秀的軟件工程師,必備技術(shù)棧之一就是對遠(yuǎn)程網(wǎng)絡(luò)協(xié)議有一定的了解
OSI七層網(wǎng)絡(luò)模型
一般我們說的網(wǎng)絡(luò)模型都是OSI網(wǎng)絡(luò)模型,而所謂的OSI網(wǎng)絡(luò)模型一般分為七層,這七層從上到下分別為(應(yīng)用層-->表示層-->會話層-->傳輸層-->網(wǎng)絡(luò)層-->數(shù)據(jù)鏈路層-->物理層):
應(yīng)用層-->表示層-->會話層-->傳輸層-->網(wǎng)絡(luò)層-->數(shù)據(jù)鏈路層-->物理層
大概的訪問調(diào)用如圖所示:

有圖可以看出,OSI的網(wǎng)絡(luò)模型將每一個步驟分的特別細(xì)致,而在我們開發(fā)過程中,最常接觸到的一般是基于OSI的二層協(xié)議--TCP/IP協(xié)議
TCP/IP四層(五層)網(wǎng)絡(luò)模型
看到這個標(biāo)題一定會有人奇怪,到底是四層還是五層模型啊,其實TCP/IP基于OSI的模型,將其中一部分操作合并為一個模型,而傳統(tǒng)認(rèn)為是四層模型,分別為:
應(yīng)用層-->傳輸層-->網(wǎng)絡(luò)層-->網(wǎng)絡(luò)接口層
即與OSI對應(yīng)的模型關(guān)系如下:

而有些人認(rèn)為網(wǎng)絡(luò)接口層不應(yīng)該合并數(shù)據(jù)鏈路層和物理層,這兩層在表現(xiàn)上是不同的,所以就有了五層模型,三種模型之間的比較圖如下:

TCP/IP請求流程
弄懂了TCP/IP大概的模型,我們來思考一個問題,即這四層模型分別是用來干啥的?又做了什么處理?在思考這些問題之前,我們先來了解這四層網(wǎng)絡(luò)模型分別包括哪些東西
應(yīng)用層
超文本傳輸協(xié)議(HTTP):萬維網(wǎng)的基本協(xié)議
文件傳輸(TFTP簡單文件傳輸協(xié)議)
遠(yuǎn)程登錄(Telnet),提供遠(yuǎn)程訪問其它主機(jī)功能,它允許用戶登錄
internet主機(jī),并在這臺主機(jī)上執(zhí)行命令.
網(wǎng)絡(luò)管理(SNMP簡單網(wǎng)絡(luò)管理協(xié)議),該協(xié)議提供了監(jiān)控網(wǎng)絡(luò)設(shè)備的方法,以及配置管理,統(tǒng)計信息收集,性能管理及安全管理等.
域名系統(tǒng)(DNS),該系統(tǒng)用于在internet中將域名及其公共廣播的網(wǎng)絡(luò)節(jié)點轉(zhuǎn)換成IP地址
網(wǎng)絡(luò)層
Internet協(xié)議(IP)
Internet控制信息協(xié)議(ICMP)
地址解析協(xié)議(ARP)
反向地址解析協(xié)議(RARP)
網(wǎng)絡(luò)接口層
網(wǎng)絡(luò)訪問層又稱作主機(jī)到網(wǎng)絡(luò)層(host-to-network).網(wǎng)絡(luò)訪問層的功能包括IP地址與物理地址硬件的映射,以及將IP封裝成幀.基于不同硬件類型的網(wǎng)絡(luò)接口,網(wǎng)絡(luò)訪問層定義了和物理介質(zhì)的連接
接下來,我們看看一個完整請求打來后,TCP/IP的四層模型的大概處理流程是什么:

從上圖我們可以看到,當(dāng)客戶端發(fā)起請求的時候(應(yīng)用層),傳輸層會根據(jù)你發(fā)來的請求,將請求中添加Tcp頭信息,并且傳遞倒網(wǎng)絡(luò)層,在網(wǎng)絡(luò)層中,會將當(dāng)前請求處理/計算(獲取出ip地址等信息),添加Ip首部信息到請求中,接著傳遞到了數(shù)據(jù)鏈路層,在這一層中我們會依照IP地址再去給當(dāng)前請求計算出一個mac碼,由于IP還存在重復(fù)的情況,而MAC地址是唯一的,這個時候?qū)AC首部信息加入請求中,根據(jù)當(dāng)前的請求就可以識別出唯一的請求了。
當(dāng)數(shù)據(jù)傳輸?shù)椒?wù)端的時候,會將傳遞來的request請求進(jìn)行解析,但是需要注意的是這里解析的順序與請求的順序相反,首先從數(shù)據(jù)鏈路層解析掉MAC首部信息,將剩下的請求信息繼續(xù)往上傳遞,然后解析Ip首部信息,再去解析Tcp首部信息、端口和請求報文參數(shù)等,根據(jù)端口等找到對應(yīng)的進(jìn)程,進(jìn)行響應(yīng)操作,這樣就是一個完整的調(diào)度流程
ARP尋址協(xié)議
上面我們有介紹到封裝請求的過程中,我們首先將IP首部信息存入請求中,然后再去存入MAC首部信息,這里不禁會有一個疑惑,IP和MAC有什么關(guān)系嗎?其實我們?nèi)魏我慌_設(shè)備都會有一個MAC和一個IP信息進(jìn)行對應(yīng),客戶端發(fā)起請求的時候,會利用一個ARP尋址協(xié)議的方式找到IP對應(yīng)的MAC信息,此協(xié)議大至如下:當(dāng)我們已知機(jī)器的IP的時候,發(fā)起一個基于當(dāng)前IP的廣播消息,而對應(yīng)IP的機(jī)器收到廣播后會返回響應(yīng)信息,即當(dāng)前機(jī)器對應(yīng)的MAC首部信息,這樣就可以根據(jù)IP獲取到MAC首部信息
注意:為了防止每一次都會發(fā)起ARP尋址,本地機(jī)器會有緩存策略,一般來說當(dāng)我們的IP信息進(jìn)行變更以后,緩存信息就會失效,這個時候才會重新進(jìn)行ARP尋址
分層負(fù)載
分布式開發(fā)的過程中,經(jīng)常聽到一個專業(yè)名詞即--二層負(fù)載/四層負(fù)載/七層負(fù)載,其實這里的xxx層負(fù)載就是指的是負(fù)載均衡方案所在的網(wǎng)絡(luò)協(xié)議的層級(針對與服務(wù)端解析的層級--逆向?qū)蛹墸?/p>
二層負(fù)載
二層負(fù)載協(xié)議,一般來說是針對MAC首部信息做的負(fù)載均衡,例如當(dāng)前有一個集群,我們希望外部訪問的時候IP地址是一樣的,但是機(jī)器的MAC不一致,保證請求分發(fā)到每一臺機(jī)器上,這時候可以提供一個虛擬的MAC首部信息,解析請求中的MAC信息的時候,將MAC信息修改為集群中需要被分發(fā)的機(jī)器的真實MAC首部信息,從而達(dá)到負(fù)載均衡的效果
三層負(fù)載
三層負(fù)載指的是針對IP層級的負(fù)載,和MAC負(fù)載(二層負(fù)載)很相似,負(fù)載均衡服務(wù)器對外提供一個虛擬IP首部信息,當(dāng)解析請求的時候,修改虛擬IP為真實的被分發(fā)的機(jī)器的IP,達(dá)到負(fù)載均衡的效果
四層負(fù)載
四層負(fù)載針對在OSI模型的傳輸層中,這一層中一般都是TCP/UDP這類的協(xié)議,而這一層一般都是封裝了當(dāng)前客戶端的請求報文信息(包含源IP,目標(biāo)IP,當(dāng)前端口號以及目標(biāo)端口號等),所以四層負(fù)載的實現(xiàn)方案一般都是接受到請求信息以后,修改請求數(shù)據(jù)中的IP/端口號的信息,來分發(fā)到不同的應(yīng)用程序中(此類負(fù)載均衡例如:Nginx)
七層負(fù)載
除了上面常見的幾種負(fù)載均衡以外,還有一種特殊的負(fù)載,叫七層負(fù)載,這種負(fù)載一般是在應(yīng)用層做的操作,而應(yīng)用層一般都是客戶端請求交互層,這一層中一般只有HTTP/DNS等協(xié)議,所以在當(dāng)前層,我們可以做到的負(fù)載條件很多,比如根據(jù)不同的URL,不同的請求類型等都可以實現(xiàn)分發(fā)到不同的服務(wù)器上
TCP/IP的握手協(xié)議與揮手協(xié)議
三次握手
tcp的連接是通過三次握手協(xié)議完成有效連接建立的,所謂的三次握手就是客戶端和服務(wù)端在連接過程中,總共發(fā)送三個包來相互之間確認(rèn)并建立聯(lián)系,而在sokect編程中,握手的過程由connect來觸發(fā)

上圖我們可以看出來三次握手的過程為:
第一次握手:客戶端發(fā)送了一個SYN為1標(biāo)志包,指明客戶端將要連接的服務(wù)器端口,并且初始化序號X保存在序列號(Sequence Number)字段中,發(fā)送完畢以后,客戶端的狀態(tài)變更為SYN-SENT
第二次握手:服務(wù)器收到了客戶端的請求,發(fā)送回確認(rèn)包標(biāo)志ACK以及客戶端發(fā)送來的SYN應(yīng)答為1,并且服務(wù)端選擇ISN序列號Y,存放到Seq中,將確認(rèn)的序列號(Acknowledgement Number)設(shè)置為客戶端發(fā)來sql+1,當(dāng)發(fā)送完畢后,服務(wù)端狀態(tài)變更為SYN-RCVD
第三次握手:客戶端再次確認(rèn)ACK,Ack為1,并且把服務(wù)端的ACK+1放在序列seq中,將服務(wù)端的序列+1放入確認(rèn)字段ack中,在發(fā)送完畢以后,客戶端俄日ESTAB-LISHED狀態(tài),當(dāng)服務(wù)端也收到這個確認(rèn)包以后,也會進(jìn)入ESTAB-LISHED狀態(tài),此時握手結(jié)束
四次揮手
與連接的時候三次握手不同,斷開連接的時候需要四次揮手的過程才能保證一定是關(guān)閉連接:

第一次揮手:客戶端需要斷開連接的時候,發(fā)送一個FIN為1的包,表示我已經(jīng)沒有數(shù)據(jù)需要發(fā)送了,可以準(zhǔn)備斷開連接,但是這個時候我還可以接受你的數(shù)據(jù),當(dāng)發(fā)送完畢后,狀態(tài)為FIN-WAIT-1
第二次揮手:服務(wù)端拿到了客戶端發(fā)來的FIN標(biāo)志位,發(fā)送一個確認(rèn)包,表示當(dāng)前已經(jīng)收到了你的關(guān)閉連接的請求,ACK為1,生成seq序列,并且將客戶端發(fā)來的seq+1作為ack確認(rèn)字段進(jìn)行應(yīng)答,發(fā)送完畢后服務(wù)端狀態(tài)為CLOSE-WIAT狀態(tài),當(dāng)客戶端受到應(yīng)答以后,狀態(tài)變更為FIN-WAIT-2,但是這個時候服務(wù)端還沒關(guān)閉,可能還存在需要發(fā)送的數(shù)據(jù)
第三次揮手:當(dāng)服務(wù)端沒有數(shù)據(jù)需要發(fā)送的時候,會再次發(fā)送一個包,F(xiàn)IN為1,ACK為1,生成序列seq,并且將上一次的ack確認(rèn)字段繼續(xù)發(fā)送過來,發(fā)送完畢后,服務(wù)端處于LAST-ACK狀態(tài)
第四次揮手:客戶端收到了來自服務(wù)端的將要關(guān)閉的包,并發(fā)出一個確認(rèn)包,將服務(wù)端的ack作為seq,并且將服務(wù)端的seq+1作為ack確認(rèn)字段再次發(fā)送過去,這個時候客戶端會進(jìn)入TIME-WAIT狀態(tài),并等待2MSL時間,這個時候服務(wù)端收到了響應(yīng),就會關(guān)閉連接,或者等待了2MSL以后,客戶端沒有收到響應(yīng),也會認(rèn)為服務(wù)端已經(jīng)關(guān)閉,也會進(jìn)行關(guān)閉操作
SYN攻擊
在三次握手的過程中,服務(wù)端發(fā)送了ack確認(rèn)字段給客戶端后,收到ack的客戶端連接稱之為半連接,如果這個時候客戶端不返回確認(rèn)包,那么服務(wù)端會重發(fā)直到超時,但是如果段時間內(nèi)偽造大量的不存在的客戶端ip發(fā)起連接請求,服務(wù)端等待客戶端確認(rèn)一直等待不到,所以短時間內(nèi)大量無用的連接占用隊列,導(dǎo)致正常的用戶連接阻塞導(dǎo)致網(wǎng)絡(luò)癱瘓,SYN攻擊是最常見的DDoS攻擊,所以有效的檢測SYN攻擊和防護(hù)很重要,防護(hù)方案常見如下:
1.過濾網(wǎng)關(guān)防護(hù) 2.加固TCP/IP協(xié)議線
為什么TCP/IP是三次握手,不是二次也不是四次?
三次握手是因為因為當(dāng) Server 端收到 Client 端的 SYN 連接請求報文后,可以直接發(fā)送
SYN+ACK 報文。其中 ACK 報文是用來應(yīng)答的,SYN 報文是用來同步的。但是關(guān)閉連接時,
當(dāng) Server 端收到 FIN 報文時,很可能并不會立即關(guān)閉 SOCKET(因為可能還有消息沒處理
完),所以只能先回復(fù)一個 ACK 報文,告訴 Client 端,"你發(fā)的 FIN 報文我收到了"。只有等到
我 Server 端所有的報文都發(fā)送完了,我才能發(fā)送 FIN 報文,因此不能一起發(fā)送。故需要四步
握手
為什么四次揮手以后還要等待2MSL才正式關(guān)閉?
網(wǎng)絡(luò)是不可靠的,雖然收到服務(wù)端的確認(rèn)以后,客戶端發(fā)出確認(rèn)以后已經(jīng)可以close,但是,可能出現(xiàn)失敗需要重試或者網(wǎng)絡(luò)卡頓導(dǎo)致,客戶端發(fā)出時間接近一次MSL時間,服務(wù)端返回也接近MSL時間,可能性都有,所以為了保險起見,等待到兩個最大的時間后還收不到返回的消息,才可以認(rèn)為是服務(wù)端關(guān)閉了
TCP的IO通信原理
雙工協(xié)議
TCP 是一個全雙工協(xié)議,數(shù)據(jù)通信允許數(shù)據(jù)同時在兩個方向上傳輸,因此全雙工是兩個單工
通信方式的結(jié)合,它要求發(fā)送設(shè)備和接收設(shè)備都有獨立的接收和發(fā)送能力,常見的協(xié)議如下:
協(xié)議概念單工協(xié)議數(shù)據(jù)傳輸只支持?jǐn)?shù)據(jù)在一個方向傳輸半雙工協(xié)議數(shù)據(jù)傳輸允許數(shù)據(jù)在兩個方向傳輸,但是在某個時刻,只能在一個方向傳輸全雙工協(xié)議允許數(shù)據(jù)同時在兩個方向上傳輸,要求設(shè)備有獨立的接收和發(fā)送的能力
IO通信過程
TCP、UDP 都是在基于Socket 概念上為某類應(yīng)用場景而擴(kuò)展出的傳輸協(xié)議,而socket 是一種
抽象層,應(yīng)用程序通過它來發(fā)送和接收數(shù)據(jù),就像應(yīng)用程序打開一個文件句柄,把數(shù)據(jù)讀寫
到磁盤上一樣。使用 socket 可以把應(yīng)用程序添加到網(wǎng)絡(luò)中,并與處于同一個網(wǎng)絡(luò)中的其他應(yīng)
用程序進(jìn)行通信。不同類型的 Socket 與不同類型的底層協(xié)議簇有關(guān)聯(lián)。主要的 socket 類型
為流套接字(stream socket)和數(shù)據(jù)報文套接字(datagram socket)。 stream socket 把 TCP作為端對端協(xié)議(底層使用 IP 協(xié)議),提供一個可信賴的字節(jié)流服務(wù)。數(shù)據(jù)報文套接字
(datagram socket)使用 UDP 協(xié)議(底層同樣使用 IP 協(xié)議)提供了一種“盡力而為”的數(shù)據(jù)
報文服務(wù),了解了Socket以后,我們來了解下tcp的io通信過程:
對于 TCP 通信來說,每個 TCP Socket 的內(nèi)核中都有一個發(fā)送緩沖區(qū)和一個接收緩沖
區(qū),TCP 的全雙工的工作模式及 TCP 的滑動窗口就是依賴于這兩個獨立的 Buffer 和該 Buffer
的填充狀態(tài)。而接收緩沖區(qū)把數(shù)據(jù)緩存到內(nèi)核,若應(yīng)用程序一直不調(diào)用Socket的read方法讀取,那么則該數(shù)據(jù)一直存在緩沖區(qū)中,而read方法就是把數(shù)據(jù)復(fù)制到應(yīng)用層的buffer中。而調(diào)用send方法的時候一般是把數(shù)據(jù)從應(yīng)用層的buffer中,讀取到Socket內(nèi)核緩沖區(qū),將數(shù)據(jù)返回,但是如果應(yīng)用一直不讀取,那么buffer滿了以后,如果對端的窗口關(guān)閉,tcp緩存區(qū)的數(shù)據(jù)不會移除,這也證實了TC是可靠傳輸?shù)摹H绻麄鬏數(shù)臄?shù)據(jù)超過了窗口的大小,那么接收方會把剩下的數(shù)據(jù)丟棄


滑動窗口
早期的網(wǎng)絡(luò)通信過程中,由于不會考慮到網(wǎng)絡(luò)擁擠的情況導(dǎo)致數(shù)據(jù)丟失而直接發(fā)送數(shù)據(jù),所以后來為了解決這個問題,就出了一個流量控制技術(shù)--滑動窗口協(xié)議,發(fā)送方和接收方都要維護(hù)一個數(shù)據(jù)幀的序列,這個序列稱之為窗口
窗口尺寸:可以不等待應(yīng)答而繼續(xù)發(fā)送數(shù)據(jù)的最大的幀稱之為窗口尺寸
發(fā)送窗口:可以不等待應(yīng)答繼續(xù)發(fā)送的窗口
接受窗口:接受發(fā)送來的數(shù)據(jù),落在當(dāng)前窗口中的幀,一定會被處理,但是落在窗口外的數(shù)據(jù),允許被丟棄的窗口
這點可以參照在線的滑動窗口演示:
https://media.pearsoncmg.com/aw/ecs_kurose_compnetwork_7/cw/content/interactiveanimations/selective-repeat-protocol/index.html