享學(xué)課堂作者:逐夢(mèng)々少年
轉(zhuǎn)載請(qǐng)聲明出處!
現(xiàn)代互聯(lián)網(wǎng)開(kāi)發(fā)過(guò)程中,無(wú)論是什么架構(gòu)系統(tǒng),無(wú)法避免的并且很重要的一個(gè)環(huán)節(jié)就是網(wǎng)絡(luò)通訊,好的網(wǎng)絡(luò)通訊方案和協(xié)議會(huì)讓整個(gè)程序效率和耗時(shí)變得更低,而JAVA開(kāi)發(fā)過(guò)程中我們一般接觸到的都是基于TCP/IP的網(wǎng)絡(luò)協(xié)議,所以一個(gè)優(yōu)秀的軟件工程師,必備技術(shù)棧之一就是對(duì)遠(yuǎn)程網(wǎng)絡(luò)協(xié)議有一定的了解
OSI七層網(wǎng)絡(luò)模型
一般我們說(shuō)的網(wǎng)絡(luò)模型都是OSI網(wǎng)絡(luò)模型,而所謂的OSI網(wǎng)絡(luò)模型一般分為七層,這七層從上到下分別為(應(yīng)用層-->表示層-->會(huì)話層-->傳輸層-->網(wǎng)絡(luò)層-->數(shù)據(jù)鏈路層-->物理層):
應(yīng)用層-->表示層-->會(huì)話層-->傳輸層-->網(wǎng)絡(luò)層-->數(shù)據(jù)鏈路層-->物理層
大概的訪問(wèn)調(diào)用如圖所示:
有圖可以看出,OSI的網(wǎng)絡(luò)模型將每一個(gè)步驟分的特別細(xì)致,而在我們開(kāi)發(fā)過(guò)程中,最常接觸到的一般是基于OSI的二層協(xié)議--TCP/IP協(xié)議
TCP/IP四層(五層)網(wǎng)絡(luò)模型
看到這個(gè)標(biāo)題一定會(huì)有人奇怪,到底是四層還是五層模型啊,其實(shí)TCP/IP基于OSI的模型,將其中一部分操作合并為一個(gè)模型,而傳統(tǒng)認(rèn)為是四層模型,分別為:
應(yīng)用層-->傳輸層-->網(wǎng)絡(luò)層-->網(wǎng)絡(luò)接口層
即與OSI對(duì)應(yīng)的模型關(guān)系如下:
而有些人認(rèn)為網(wǎng)絡(luò)接口層不應(yīng)該合并數(shù)據(jù)鏈路層和物理層,這兩層在表現(xiàn)上是不同的,所以就有了五層模型,三種模型之間的比較圖如下:
TCP/IP請(qǐng)求流程
弄懂了TCP/IP大概的模型,我們來(lái)思考一個(gè)問(wèn)題,即這四層模型分別是用來(lái)干啥的?又做了什么處理?在思考這些問(wèn)題之前,我們先來(lái)了解這四層網(wǎng)絡(luò)模型分別包括哪些東西
應(yīng)用層
超文本傳輸協(xié)議(HTTP):萬(wàn)維網(wǎng)的基本協(xié)議
文件傳輸(TFTP簡(jiǎn)單文件傳輸協(xié)議)
遠(yuǎn)程登錄(Telnet),提供遠(yuǎn)程訪問(wèn)其它主機(jī)功能,它允許用戶登錄
internet主機(jī),并在這臺(tái)主機(jī)上執(zhí)行命令.
網(wǎng)絡(luò)管理(SNMP簡(jiǎn)單網(wǎng)絡(luò)管理協(xié)議),該協(xié)議提供了監(jiān)控網(wǎng)絡(luò)設(shè)備的方法,以及配置管理,統(tǒng)計(jì)信息收集,性能管理及安全管理等.
域名系統(tǒng)(DNS),該系統(tǒng)用于在internet中將域名及其公共廣播的網(wǎng)絡(luò)節(jié)點(diǎn)轉(zhuǎn)換成IP地址
網(wǎng)絡(luò)層
Internet協(xié)議(IP)
Internet控制信息協(xié)議(ICMP)
地址解析協(xié)議(ARP)
反向地址解析協(xié)議(RARP)
網(wǎng)絡(luò)接口層
網(wǎng)絡(luò)訪問(wèn)層又稱作主機(jī)到網(wǎng)絡(luò)層(host-to-network).網(wǎng)絡(luò)訪問(wèn)層的功能包括IP地址與物理地址硬件的映射,以及將IP封裝成幀.基于不同硬件類型的網(wǎng)絡(luò)接口,網(wǎng)絡(luò)訪問(wèn)層定義了和物理介質(zhì)的連接
接下來(lái),我們看看一個(gè)完整請(qǐng)求打來(lái)后,TCP/IP的四層模型的大概處理流程是什么:
從上圖我們可以看到,當(dāng)客戶端發(fā)起請(qǐng)求的時(shí)候(應(yīng)用層),傳輸層會(huì)根據(jù)你發(fā)來(lái)的請(qǐng)求,將請(qǐng)求中添加Tcp頭信息,并且傳遞倒網(wǎng)絡(luò)層,在網(wǎng)絡(luò)層中,會(huì)將當(dāng)前請(qǐng)求處理/計(jì)算(獲取出ip地址等信息),添加Ip首部信息到請(qǐng)求中,接著傳遞到了數(shù)據(jù)鏈路層,在這一層中我們會(huì)依照IP地址再去給當(dāng)前請(qǐng)求計(jì)算出一個(gè)mac碼,由于IP還存在重復(fù)的情況,而MAC地址是唯一的,這個(gè)時(shí)候?qū)AC首部信息加入請(qǐng)求中,根據(jù)當(dāng)前的請(qǐng)求就可以識(shí)別出唯一的請(qǐng)求了。
當(dāng)數(shù)據(jù)傳輸?shù)椒?wù)端的時(shí)候,會(huì)將傳遞來(lái)的request請(qǐng)求進(jìn)行解析,但是需要注意的是這里解析的順序與請(qǐng)求的順序相反,首先從數(shù)據(jù)鏈路層解析掉MAC首部信息,將剩下的請(qǐng)求信息繼續(xù)往上傳遞,然后解析Ip首部信息,再去解析Tcp首部信息、端口和請(qǐng)求報(bào)文參數(shù)等,根據(jù)端口等找到對(duì)應(yīng)的進(jìn)程,進(jìn)行響應(yīng)操作,這樣就是一個(gè)完整的調(diào)度流程
ARP尋址協(xié)議
上面我們有介紹到封裝請(qǐng)求的過(guò)程中,我們首先將IP首部信息存入請(qǐng)求中,然后再去存入MAC首部信息,這里不禁會(huì)有一個(gè)疑惑,IP和MAC有什么關(guān)系嗎?其實(shí)我們?nèi)魏我慌_(tái)設(shè)備都會(huì)有一個(gè)MAC和一個(gè)IP信息進(jìn)行對(duì)應(yīng),客戶端發(fā)起請(qǐng)求的時(shí)候,會(huì)利用一個(gè)ARP尋址協(xié)議的方式找到IP對(duì)應(yīng)的MAC信息,此協(xié)議大至如下:當(dāng)我們已知機(jī)器的IP的時(shí)候,發(fā)起一個(gè)基于當(dāng)前IP的廣播消息,而對(duì)應(yīng)IP的機(jī)器收到廣播后會(huì)返回響應(yīng)信息,即當(dāng)前機(jī)器對(duì)應(yīng)的MAC首部信息,這樣就可以根據(jù)IP獲取到MAC首部信息
注意:為了防止每一次都會(huì)發(fā)起ARP尋址,本地機(jī)器會(huì)有緩存策略,一般來(lái)說(shuō)當(dāng)我們的IP信息進(jìn)行變更以后,緩存信息就會(huì)失效,這個(gè)時(shí)候才會(huì)重新進(jìn)行ARP尋址
分層負(fù)載
分布式開(kāi)發(fā)的過(guò)程中,經(jīng)常聽(tīng)到一個(gè)專業(yè)名詞即--二層負(fù)載/四層負(fù)載/七層負(fù)載,其實(shí)這里的xxx層負(fù)載就是指的是負(fù)載均衡方案所在的網(wǎng)絡(luò)協(xié)議的層級(jí)(針對(duì)與服務(wù)端解析的層級(jí)--逆向?qū)蛹?jí))
二層負(fù)載
二層負(fù)載協(xié)議,一般來(lái)說(shuō)是針對(duì)MAC首部信息做的負(fù)載均衡,例如當(dāng)前有一個(gè)集群,我們希望外部訪問(wèn)的時(shí)候IP地址是一樣的,但是機(jī)器的MAC不一致,保證請(qǐng)求分發(fā)到每一臺(tái)機(jī)器上,這時(shí)候可以提供一個(gè)虛擬的MAC首部信息,解析請(qǐng)求中的MAC信息的時(shí)候,將MAC信息修改為集群中需要被分發(fā)的機(jī)器的真實(shí)MAC首部信息,從而達(dá)到負(fù)載均衡的效果
三層負(fù)載
三層負(fù)載指的是針對(duì)IP層級(jí)的負(fù)載,和MAC負(fù)載(二層負(fù)載)很相似,負(fù)載均衡服務(wù)器對(duì)外提供一個(gè)虛擬IP首部信息,當(dāng)解析請(qǐng)求的時(shí)候,修改虛擬IP為真實(shí)的被分發(fā)的機(jī)器的IP,達(dá)到負(fù)載均衡的效果
四層負(fù)載
四層負(fù)載針對(duì)在OSI模型的傳輸層中,這一層中一般都是TCP/UDP這類的協(xié)議,而這一層一般都是封裝了當(dāng)前客戶端的請(qǐng)求報(bào)文信息(包含源IP,目標(biāo)IP,當(dāng)前端口號(hào)以及目標(biāo)端口號(hào)等),所以四層負(fù)載的實(shí)現(xiàn)方案一般都是接受到請(qǐng)求信息以后,修改請(qǐng)求數(shù)據(jù)中的IP/端口號(hào)的信息,來(lái)分發(fā)到不同的應(yīng)用程序中(此類負(fù)載均衡例如:Nginx)
七層負(fù)載
除了上面常見(jiàn)的幾種負(fù)載均衡以外,還有一種特殊的負(fù)載,叫七層負(fù)載,這種負(fù)載一般是在應(yīng)用層做的操作,而應(yīng)用層一般都是客戶端請(qǐng)求交互層,這一層中一般只有HTTP/DNS等協(xié)議,所以在當(dāng)前層,我們可以做到的負(fù)載條件很多,比如根據(jù)不同的URL,不同的請(qǐng)求類型等都可以實(shí)現(xiàn)分發(fā)到不同的服務(wù)器上
TCP/IP的握手協(xié)議與揮手協(xié)議
三次握手
tcp的連接是通過(guò)三次握手協(xié)議完成有效連接建立的,所謂的三次握手就是客戶端和服務(wù)端在連接過(guò)程中,總共發(fā)送三個(gè)包來(lái)相互之間確認(rèn)并建立聯(lián)系,而在sokect編程中,握手的過(guò)程由connect來(lái)觸發(fā)
上圖我們可以看出來(lái)三次握手的過(guò)程為:
第一次握手:客戶端發(fā)送了一個(gè)SYN為1標(biāo)志包,指明客戶端將要連接的服務(wù)器端口,并且初始化序號(hào)X保存在序列號(hào)(Sequence Number)字段中,發(fā)送完畢以后,客戶端的狀態(tài)變更為SYN-SENT
第二次握手:服務(wù)器收到了客戶端的請(qǐng)求,發(fā)送回確認(rèn)包標(biāo)志ACK以及客戶端發(fā)送來(lái)的SYN應(yīng)答為1,并且服務(wù)端選擇ISN序列號(hào)Y,存放到Seq中,將確認(rèn)的序列號(hào)(Acknowledgement Number)設(shè)置為客戶端發(fā)來(lái)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ù)端也收到這個(gè)確認(rèn)包以后,也會(huì)進(jìn)入ESTAB-LISHED狀態(tài),此時(shí)握手結(jié)束
四次揮手
與連接的時(shí)候三次握手不同,斷開(kāi)連接的時(shí)候需要四次揮手的過(guò)程才能保證一定是關(guān)閉連接:
第一次揮手:客戶端需要斷開(kāi)連接的時(shí)候,發(fā)送一個(gè)FIN為1的包,表示我已經(jīng)沒(méi)有數(shù)據(jù)需要發(fā)送了,可以準(zhǔn)備斷開(kāi)連接,但是這個(gè)時(shí)候我還可以接受你的數(shù)據(jù),當(dāng)發(fā)送完畢后,狀態(tài)為FIN-WAIT-1
第二次揮手:服務(wù)端拿到了客戶端發(fā)來(lái)的FIN標(biāo)志位,發(fā)送一個(gè)確認(rèn)包,表示當(dāng)前已經(jīng)收到了你的關(guān)閉連接的請(qǐng)求,ACK為1,生成seq序列,并且將客戶端發(fā)來(lái)的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,但是這個(gè)時(shí)候服務(wù)端還沒(méi)關(guān)閉,可能還存在需要發(fā)送的數(shù)據(jù)
第三次揮手:當(dāng)服務(wù)端沒(méi)有數(shù)據(jù)需要發(fā)送的時(shí)候,會(huì)再次發(fā)送一個(gè)包,F(xiàn)IN為1,ACK為1,生成序列seq,并且將上一次的ack確認(rèn)字段繼續(xù)發(fā)送過(guò)來(lái),發(fā)送完畢后,服務(wù)端處于LAST-ACK狀態(tài)
第四次揮手:客戶端收到了來(lái)自服務(wù)端的將要關(guān)閉的包,并發(fā)出一個(gè)確認(rèn)包,將服務(wù)端的ack作為seq,并且將服務(wù)端的seq+1作為ack確認(rèn)字段再次發(fā)送過(guò)去,這個(gè)時(shí)候客戶端會(huì)進(jìn)入TIME-WAIT狀態(tài),并等待2MSL時(shí)間,這個(gè)時(shí)候服務(wù)端收到了響應(yīng),就會(huì)關(guān)閉連接,或者等待了2MSL以后,客戶端沒(méi)有收到響應(yīng),也會(huì)認(rèn)為服務(wù)端已經(jīng)關(guān)閉,也會(huì)進(jìn)行關(guān)閉操作
SYN攻擊
在三次握手的過(guò)程中,服務(wù)端發(fā)送了ack確認(rèn)字段給客戶端后,收到ack的客戶端連接稱之為半連接,如果這個(gè)時(shí)候客戶端不返回確認(rèn)包,那么服務(wù)端會(huì)重發(fā)直到超時(shí),但是如果段時(shí)間內(nèi)偽造大量的不存在的客戶端ip發(fā)起連接請(qǐng)求,服務(wù)端等待客戶端確認(rèn)一直等待不到,所以短時(shí)間內(nèi)大量無(wú)用的連接占用隊(duì)列,導(dǎo)致正常的用戶連接阻塞導(dǎo)致網(wǎng)絡(luò)癱瘓,SYN攻擊是最常見(jiàn)的DDoS攻擊,所以有效的檢測(cè)SYN攻擊和防護(hù)很重要,防護(hù)方案常見(jiàn)如下:
1.過(guò)濾網(wǎng)關(guān)防護(hù) 2.加固TCP/IP協(xié)議線
為什么TCP/IP是三次握手,不是二次也不是四次?
三次握手是因?yàn)橐驗(yàn)楫?dāng) Server 端收到 Client 端的 SYN 連接請(qǐng)求報(bào)文后,可以直接發(fā)送
SYN+ACK 報(bào)文。其中 ACK 報(bào)文是用來(lái)應(yīng)答的,SYN 報(bào)文是用來(lái)同步的。但是關(guān)閉連接時(shí),
當(dāng) Server 端收到 FIN 報(bào)文時(shí),很可能并不會(huì)立即關(guān)閉 SOCKET(因?yàn)榭赡苓€有消息沒(méi)處理
完),所以只能先回復(fù)一個(gè) ACK 報(bào)文,告訴 Client 端,"你發(fā)的 FIN 報(bào)文我收到了"。只有等到
我 Server 端所有的報(bào)文都發(fā)送完了,我才能發(fā)送 FIN 報(bào)文,因此不能一起發(fā)送。故需要四步
握手
為什么四次揮手以后還要等待2MSL才正式關(guān)閉?
網(wǎng)絡(luò)是不可靠的,雖然收到服務(wù)端的確認(rèn)以后,客戶端發(fā)出確認(rèn)以后已經(jīng)可以close,但是,可能出現(xiàn)失敗需要重試或者網(wǎng)絡(luò)卡頓導(dǎo)致,客戶端發(fā)出時(shí)間接近一次MSL時(shí)間,服務(wù)端返回也接近MSL時(shí)間,可能性都有,所以為了保險(xiǎn)起見(jiàn),等待到兩個(gè)最大的時(shí)間后還收不到返回的消息,才可以認(rèn)為是服務(wù)端關(guān)閉了
TCP的IO通信原理
雙工協(xié)議
TCP 是一個(gè)全雙工協(xié)議,數(shù)據(jù)通信允許數(shù)據(jù)同時(shí)在兩個(gè)方向上傳輸,因此全雙工是兩個(gè)單工
通信方式的結(jié)合,它要求發(fā)送設(shè)備和接收設(shè)備都有獨(dú)立的接收和發(fā)送能力,常見(jiàn)的協(xié)議如下:
協(xié)議概念單工協(xié)議數(shù)據(jù)傳輸只支持?jǐn)?shù)據(jù)在一個(gè)方向傳輸半雙工協(xié)議數(shù)據(jù)傳輸允許數(shù)據(jù)在兩個(gè)方向傳輸,但是在某個(gè)時(shí)刻,只能在一個(gè)方向傳輸全雙工協(xié)議允許數(shù)據(jù)同時(shí)在兩個(gè)方向上傳輸,要求設(shè)備有獨(dú)立的接收和發(fā)送的能力
IO通信過(guò)程
TCP、UDP 都是在基于Socket 概念上為某類應(yīng)用場(chǎng)景而擴(kuò)展出的傳輸協(xié)議,而socket 是一種
抽象層,應(yīng)用程序通過(guò)它來(lái)發(fā)送和接收數(shù)據(jù),就像應(yīng)用程序打開(kāi)一個(gè)文件句柄,把數(shù)據(jù)讀寫
到磁盤上一樣。使用 socket 可以把應(yīng)用程序添加到網(wǎng)絡(luò)中,并與處于同一個(gè)網(wǎng)絡(luò)中的其他應(yīng)
用程序進(jìn)行通信。不同類型的 Socket 與不同類型的底層協(xié)議簇有關(guān)聯(lián)。主要的 socket 類型
為流套接字(stream socket)和數(shù)據(jù)報(bào)文套接字(datagram socket)。 stream socket 把 TCP作為端對(duì)端協(xié)議(底層使用 IP 協(xié)議),提供一個(gè)可信賴的字節(jié)流服務(wù)。數(shù)據(jù)報(bào)文套接字
(datagram socket)使用 UDP 協(xié)議(底層同樣使用 IP 協(xié)議)提供了一種“盡力而為”的數(shù)據(jù)
報(bào)文服務(wù),了解了Socket以后,我們來(lái)了解下tcp的io通信過(guò)程:
對(duì)于 TCP 通信來(lái)說(shuō),每個(gè) TCP Socket 的內(nèi)核中都有一個(gè)發(fā)送緩沖區(qū)和一個(gè)接收緩沖
區(qū),TCP 的全雙工的工作模式及 TCP 的滑動(dòng)窗口就是依賴于這兩個(gè)獨(dú)立的 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í)候一般是把數(shù)據(jù)從應(yīng)用層的buffer中,讀取到Socket內(nèi)核緩沖區(qū),將數(shù)據(jù)返回,但是如果應(yīng)用一直不讀取,那么buffer滿了以后,如果對(duì)端的窗口關(guān)閉,tcp緩存區(qū)的數(shù)據(jù)不會(huì)移除,這也證實(shí)了TC是可靠傳輸?shù)摹H绻麄鬏數(shù)臄?shù)據(jù)超過(guò)了窗口的大小,那么接收方會(huì)把剩下的數(shù)據(jù)丟棄
滑動(dòng)窗口
早期的網(wǎng)絡(luò)通信過(guò)程中,由于不會(huì)考慮到網(wǎng)絡(luò)擁擠的情況導(dǎo)致數(shù)據(jù)丟失而直接發(fā)送數(shù)據(jù),所以后來(lái)為了解決這個(gè)問(wèn)題,就出了一個(gè)流量控制技術(shù)--滑動(dòng)窗口協(xié)議,發(fā)送方和接收方都要維護(hù)一個(gè)數(shù)據(jù)幀的序列,這個(gè)序列稱之為窗口
窗口尺寸:可以不等待應(yīng)答而繼續(xù)發(fā)送數(shù)據(jù)的最大的幀稱之為窗口尺寸
發(fā)送窗口:可以不等待應(yīng)答繼續(xù)發(fā)送的窗口
接受窗口:接受發(fā)送來(lái)的數(shù)據(jù),落在當(dāng)前窗口中的幀,一定會(huì)被處理,但是落在窗口外的數(shù)據(jù),允許被丟棄的窗口
這點(diǎn)可以參照在線的滑動(dòng)窗口演示:
https://media.pearsoncmg.com/aw/ecs_kurose_compnetwork_7/cw/content/interactiveanimations/selective-repeat-protocol/index.html