網(wǎng)絡(luò)原理
網(wǎng)絡(luò)協(xié)議的在實(shí)際運(yùn)用是分為5層協(xié)議及:
- 應(yīng)用層
- 傳輸層
- 網(wǎng)絡(luò)層
- 數(shù)據(jù)鏈路層
- 物理層
這五層結(jié)構(gòu)在,java 網(wǎng)絡(luò)編程中已經(jīng)有所現(xiàn),具體用法具體實(shí)現(xiàn)的功能,都有。
應(yīng)用層
這里主要的一個(gè)協(xié)議也是目前網(wǎng)絡(luò)上最常用的一個(gè)協(xié)議,HTTP協(xié)議。
這層結(jié)構(gòu),決定數(shù)據(jù)要傳輸什么,拿到數(shù)據(jù)后如何使用。HTTP為什么是最長(zhǎng)用的一個(gè)應(yīng)用層協(xié)議,其本質(zhì)就是在確定框架后,程序員可以在自定義一些協(xié)議,可控性和操控大大提升。
及約定數(shù)據(jù)報(bào)的數(shù)據(jù)格式,就是在自定義協(xié)議。
而如何約定?
- 確定要傳輸那些信息(根據(jù)需求走)
- 確定數(shù)據(jù)按照啥樣的格式來組織。
-
網(wǎng)絡(luò)上傳輸?shù)?,本質(zhì)都是二進(jìn)制字符串,就需要將上述的穿輸?shù)男畔⒄蠟橐粋€(gè)字符串。但是在傳輸內(nèi)容的時(shí)候,一個(gè)我們需要的數(shù)據(jù),其實(shí)和其他數(shù)據(jù)是合在一起的。我們要如何拿到所需要的數(shù)據(jù)。很簡(jiǎn)單,我們?cè)趥鬏敂?shù)據(jù)的時(shí)候,設(shè)定一個(gè)符號(hào),或者距離單位。鎖定所需要的數(shù)據(jù)。
-
比如我規(guī)定,屬性之間用 ’,‘ 隔開 ,每個(gè)對(duì)象用 ‘\n’ 隔開,結(jié)束標(biāo)志用 ’;‘ 隔開 。
-
只要發(fā)送方發(fā)送數(shù)據(jù)按照這個(gè)格式傳輸,然后接收方,在解析數(shù)據(jù)的時(shí)候,用這個(gè)格式解析就好;
-
在開發(fā)中,有一些特定的現(xiàn)成的格式??梢灾苯幽脕硎褂谩1热缰暗囊环N典型的格式,xml ,還有現(xiàn)在用的比較多的一種格式。json,
什么是json。
{
userId:100
userPos:10-100
}
使用{}作為標(biāo)識(shí),{}里面的諾干個(gè)鍵值對(duì),每個(gè)鍵值對(duì)用 ’,‘ ,分割,鍵值對(duì),用 ’:‘ 分割。 鍵必須是字符串,值就可以是一個(gè)object。
傳輸層
先說UDP(不可靠傳輸)
這個(gè)就是UDP 的報(bào)文格式。
- 端口是2個(gè)字節(jié),所以端口可以取:0-- > 65535
- 報(bào)文長(zhǎng)度就局限了正文最大能裝多少的內(nèi)容。64KB。所以如果用UDP進(jìn)行傳輸一個(gè)很長(zhǎng)的數(shù)據(jù),就需要包一個(gè)較大的數(shù)據(jù),拆成很多分,用UDP傳輸。(很復(fù)雜)
所以用UDP傳輸數(shù)據(jù),不能太大,否則就會(huì)出現(xiàn)問題。 - 校驗(yàn)和,是為了校驗(yàn)數(shù)據(jù)的準(zhǔn)確的。在真實(shí)的網(wǎng)絡(luò)傳輸中就會(huì)遇到很多問題。磁場(chǎng),太陽風(fēng)暴,等等。這些都會(huì)干擾數(shù)據(jù)的穩(wěn)定。而校驗(yàn)和就是用來判定,當(dāng)前的數(shù)據(jù)是否出錯(cuò)。(通常是設(shè)定一種特殊的算法,比如取正文中的一些字符,然后算出一個(gè)數(shù)據(jù),然后傳輸完畢后在驗(yàn)證一次)
重點(diǎn)說明TCP(可靠傳輸)
TCP如何實(shí)現(xiàn)可靠傳輸?
一、確認(rèn)應(yīng)答
什么是確認(rèn)應(yīng)答呢?其實(shí)就很簡(jiǎn)單,比如網(wǎng)上購(gòu)物,商家發(fā)貨,貨物根據(jù)你的信息發(fā)送貨物,然后送到哪里并且,你確認(rèn)了收貨,然后平臺(tái)就會(huì)將錢給商家,這就是一個(gè)很簡(jiǎn)單的應(yīng)答模式。
這個(gè)模型有一個(gè)問題,就是網(wǎng)絡(luò)的狀況有很多種,會(huì)出現(xiàn)后發(fā)先至的問題。對(duì)應(yīng)到上述的例子就是,遇到強(qiáng)降雨,但是后邊的貨車走了另一條路。走的就比之前的車要快。
異常狀態(tài)
正常狀態(tài)
如何解決這個(gè)問題?
此時(shí)就需要對(duì)消息進(jìn)行編號(hào)。
- 給發(fā)送的消息分配一個(gè)需要
- 同時(shí)應(yīng)答報(bào)文,給出一個(gè)確認(rèn)順序
協(xié)議格式:
TCP將每個(gè)字節(jié)的數(shù)據(jù)都進(jìn)行了編號(hào),基序列號(hào)。
- 源/目的端口號(hào):表示數(shù)據(jù)是從哪個(gè)進(jìn)程來,到哪個(gè)進(jìn)程去;
- 32位序號(hào)/32位確認(rèn)號(hào):后面詳細(xì)講;
- 4位TCP報(bào)頭長(zhǎng)度:表示該TCP頭部有多少個(gè)32位bit(有多少個(gè)4字節(jié));所以TCP頭部最大長(zhǎng)度是15 * 4 = 60
- 6位標(biāo)志位:
- URG:緊急指針是否有效
- ACK:確認(rèn)號(hào)是否有效
- PSH:提示接收端應(yīng)用程序立刻從TCP緩沖區(qū)把數(shù)據(jù)讀走
- RST:對(duì)方要求重新建立連接;我們把攜帶RST標(biāo)識(shí)的稱為復(fù)位報(bào)文段
- SYN:請(qǐng)求建立連接;我們把攜帶SYN標(biāo)識(shí)的稱為同步報(bào)文段
- FIN:通知對(duì)方,本端要關(guān)閉了,我們稱攜帶FIN標(biāo)識(shí)的為結(jié)束報(bào)文段
- 16位窗口大?。汉竺嬖僬f
- 16位校驗(yàn)和:發(fā)送端填充,CRC校驗(yàn)。接收端校驗(yàn)不通過,則認(rèn)為數(shù)據(jù)有問題。此處的檢驗(yàn)和不光
- 包含TCP首部,也包含TCP數(shù)據(jù)部分。
- 16位緊急指針:標(biāo)識(shí)哪部分?jǐn)?shù)據(jù)是緊急數(shù)據(jù);
- 40字節(jié)頭部選項(xiàng):暫時(shí)忽略;
首先接送方的序號(hào)和發(fā)送方的序號(hào)無關(guān)
確認(rèn)序號(hào) 1001 的含義。
- 小于1001的數(shù)據(jù),我已經(jīng)收到
- 我接下來想要發(fā)送方從1001開始的數(shù)據(jù)
在之前說過,網(wǎng)絡(luò)傳輸?shù)臅r(shí)候,會(huì)有后發(fā)先至的情況,同樣的這個(gè)也是。但是能,TCP在傳輸時(shí)會(huì)有序號(hào),序號(hào)天然就有順序,所以對(duì)于這種情況,只要在接收方接收前排序就好了。(優(yōu)先級(jí)隊(duì)列就能完成這個(gè))、
對(duì)于TCP來說,自身也承擔(dān)了這個(gè)整隊(duì)的任務(wù),TCP會(huì)有一個(gè)緩沖區(qū)(內(nèi)核中的一個(gè)區(qū)域),每個(gè)socket都有自己的緩沖區(qū)。然后TCP就可以按照序號(hào)針對(duì)收到的消息進(jìn)行針對(duì)。
如果一切順利就可以應(yīng)答了??蓡栴}就是,現(xiàn)實(shí)并不順利。比如丟包。
二、超時(shí)重傳
那么什么是丟包呢?
傳輸數(shù)據(jù)的時(shí)候要經(jīng)過各個(gè)節(jié)點(diǎn),可是問題來了,一臺(tái)機(jī)器節(jié)點(diǎn)的轉(zhuǎn)發(fā)能力是有極限的,也就是說到達(dá)極限的機(jī)器,就可能會(huì)引起丟包的問題。(實(shí)時(shí)性的APP或者應(yīng)用對(duì)于丟包的問題非常的敏感),如果丟包了接收方就收不到了。自然就不會(huì)返回ACK。
如何解決?文章來源:http://www.zghlxwxcb.cn/news/detail-702073.html
之前的邏輯,就是發(fā)送方發(fā)送消息會(huì)受到一個(gè)接收者的反饋的接收信息。但是丟包了,數(shù)據(jù)就不完整了。在隊(duì)列里之前排好序的數(shù)據(jù),因?yàn)閬G包使得,序列并不完整。
此時(shí)因?yàn)樾蛄胁⒉煌暾筒粫?huì)交給接收者。然后序列就會(huì)等待,如果此時(shí)的序列等待時(shí)間長(zhǎng)了,發(fā)送方遲遲拿不到應(yīng)答。那么發(fā)送方就知道,傳輸出了問題,那么就會(huì)重新再發(fā)一次。直到拿到應(yīng)答。(這個(gè)就叫超時(shí)重傳)
有一個(gè)細(xì)節(jié):
- 數(shù)據(jù)直接丟失,接收方?jīng)]收到,自然不會(huì)發(fā) ack
- 接收方接收到數(shù)據(jù)了,但是返回的ack 卻丟了。
此時(shí)發(fā)送方分不清這些情況,只能重傳。
可是此時(shí),接收方已經(jīng)在緩沖區(qū)中有了數(shù)據(jù),再傳一個(gè),就重復(fù)了。此時(shí)接收方的緩沖區(qū),會(huì)根據(jù)數(shù)據(jù)的序列,自動(dòng)去重。保證應(yīng)用程序中讀到的數(shù)據(jù)任然只有一份
如果多次重復(fù)發(fā)送還沒有收到ack 那么多半網(wǎng)絡(luò)出了問題。主要是假設(shè)丟包率為10%,那么連續(xù)兩次丟包,概率就是10% * 10%=1%
而以上這兩種機(jī)制就是,TCP的可靠性保障。及:
- 確認(rèn)應(yīng)答
- 超時(shí)重傳
三、鏈接管理
TCP創(chuàng)建鏈接:三次握手
TCP斷開鏈接:四次揮手
建立連接
什么是三次握手?
握手是指通信雙方,進(jìn)行一次網(wǎng)絡(luò)交互。相當(dāng)于客戶端和服務(wù)器之間,通過三次交互,建立連接關(guān)系(雙方各自記錄了對(duì)方的信息)
互相應(yīng)答,確保雙方的網(wǎng)絡(luò)是完整的。并建立連接(有那么一滴滴可靠性的說法,但并不是)
等建立連接完畢,服務(wù)器 accept 把建立好的鏈接從內(nèi)核拿到應(yīng)用程序中。
- 此時(shí)如果ACK 為 1 ,則表示當(dāng)前的TCP數(shù)據(jù)報(bào)為一個(gè)應(yīng)答報(bào)文
- 此時(shí)如果SYN為 1 ,則表示當(dāng)前的TCP數(shù)據(jù)報(bào)為一個(gè)同步報(bào)文
- 如果ACK和SYN都是 1 ,則這個(gè)報(bào)文就是 SYN + ACK
做這么多。其實(shí)就是驗(yàn)證自己的發(fā)送能力和接收能力是否正常。
斷開鏈接
什么是四次揮手?
通信的雙方,各自給對(duì)方發(fā)一個(gè)FIN(結(jié)束報(bào)文),在各自給對(duì)方放回ACK
建立連接,一定是客戶端發(fā)起,但是斷開鏈接客戶端和服務(wù)器都有可能。(并且通常ACK與FIN并不能重合)(FIN比特位位1的時(shí)候)
注意:
三次握手:ack與syn是同一個(gè)時(shí)機(jī)觸發(fā)的(都是由內(nèi)核完成)
四次握手:ack與fin內(nèi)是不同時(shí)機(jī)出發(fā)的。前者由內(nèi)核完成,而后者需要程序中 socke t的 close 方法才會(huì)觸發(fā)fin、
四、滑動(dòng)窗口
是為了解決,數(shù)據(jù)傳輸?shù)男蕟栴}。
對(duì)每一個(gè)發(fā)送的數(shù)據(jù)段,都要給一個(gè)ACK確認(rèn)應(yīng)答。收到ACK后再發(fā)送下一個(gè)數(shù)據(jù)段。這樣做有一個(gè)比較大的缺點(diǎn),就是性能較差。尤其是數(shù)據(jù)往返的時(shí)間較長(zhǎng)的時(shí)候。
可靠性的提升,往往代表,效率的損失。
可以看到,客戶端A這邊傳輸5000個(gè)字節(jié),要應(yīng)答四次。此時(shí)A就用了大量的時(shí)間去等待ACK
既然這樣一發(fā)一收的方式性能較低,那么我們一次發(fā)送多條數(shù)據(jù),就可以大大的提高性能(其實(shí)是將多個(gè)段的等待時(shí)間重疊在一起了)
此時(shí)將數(shù)據(jù)進(jìn)行批量發(fā)送。統(tǒng)一發(fā)送后,一起等待ACK的返回。這個(gè)批量傳輸?shù)倪^程就是滑動(dòng)窗口
等待的傳輸數(shù)據(jù)到達(dá)一定的數(shù)量,而這個(gè)批量等待的數(shù)據(jù)稱為————》窗口大小
白色區(qū)域,相當(dāng)于等待的窗口~~
批量發(fā)送了四個(gè)數(shù)據(jù),就等待四個(gè)ACK。
這個(gè)批量發(fā)送也會(huì)出現(xiàn)問題。
比如:
- 數(shù)據(jù)包以抵達(dá),而ACK卻丟了
這種情況,即使丟了這么多的ack,對(duì)于可靠性也沒有任何影響。
確認(rèn)序號(hào)的意思是指,該序號(hào)之前的數(shù)據(jù)都已經(jīng)收到了,后一個(gè) ACK 能表示前面的 ACK。(覆蓋了)
- 數(shù)據(jù)包就直接丟了
解釋:由于剛才1001 - 2000 這個(gè)數(shù)據(jù)丟了,所以接收方任然要索要1001,不會(huì)說因?yàn)槭盏降氖?001-3000,就返回3001。接下來幾次的數(shù)據(jù) ack ,確認(rèn)序號(hào)都是1001, B 再次向 A 反復(fù)索要 1001 這個(gè)數(shù)據(jù),A這邊識(shí)別到多個(gè) 1001 的請(qǐng)求,就知道 1001-2000丟了。于是 A 就重傳了 1001-2000 這個(gè)數(shù)據(jù)。
當(dāng) A 1001-2000 這個(gè)數(shù)據(jù)重傳后,B 收到了就會(huì) 傳一個(gè)7001這個(gè)ACK,因?yàn)椋瑪?shù)據(jù)只是缺了1001-2000這一段,補(bǔ)上之后,不用傳關(guān)于這個(gè)段的 ACK,根據(jù)滑動(dòng)窗口特點(diǎn),后一個(gè) ACK 就能表示他前面的數(shù)據(jù)已經(jīng)到達(dá) B。也就是,雖然1001-2000這一段沒收到,但是其他的還在收啊。只是沒有應(yīng)答。補(bǔ)上了之后就開始應(yīng)答。
這個(gè)重傳的過程也叫:快速重傳。
五、流量控制(也是保證可靠性的機(jī)制)
按道理來說,窗口越大,意味著,批量傳輸數(shù)據(jù)越多,也就意味著整體速度越快。但是數(shù)據(jù)多,就不意味著安全可靠。
數(shù)據(jù)一次性發(fā)的多,而快,一下子就把接收緩沖區(qū)給充滿了。如果繼續(xù)發(fā)送數(shù)據(jù),此時(shí)就會(huì)丟包。這個(gè)時(shí)候,就需要控制一下流量
當(dāng)ACK為1的時(shí)候,窗口大小字段就會(huì)生效。這里16位窗口是建議。
重要:發(fā)送方的窗口大小 = 流量控制 + 擁塞控制
如此就達(dá)成了阻塞的效果。
六、阻塞控制
滑動(dòng)窗口大小 = 流量控制 + 擁塞控制
流量控制:平衡了接收方的處理能力
阻塞控制:衡量了傳輸路勁的處理能力
在java網(wǎng)絡(luò)編程的哪一章中網(wǎng)絡(luò)的傳輸是需要經(jīng)過很多個(gè)節(jié)點(diǎn)的。如果任何一個(gè)設(shè)備,處理能力達(dá)到瓶頸,都會(huì)對(duì)整體的傳輸塑料產(chǎn)生明顯影響。
而阻塞控制,就需要找到,衡量中間節(jié)點(diǎn),傳輸?shù)哪芰?。怎么找?通過一次次實(shí)驗(yàn),找到一個(gè)合適的發(fā)送速率
- 開始的時(shí)候,按照一個(gè)小的速率發(fā)送
- 如果不丟包,就可以擴(kuò)大窗口的大小
- 如果丟包,就可以縮小窗口的大小
慢開始:剛開始傳輸會(huì)給一個(gè)非常小的窗口
指數(shù)規(guī)律增長(zhǎng):每一次擴(kuò)大窗口,是翻倍成長(zhǎng)??焖俳咏W(wǎng)絡(luò)傳輸路徑的能力瓶頸。
傳輸輪次:第一次發(fā)送,第二次發(fā)送。。。。
擁塞避免,“加法增大” :指數(shù)增長(zhǎng)懂啊一定的閾值,就變成線性增長(zhǎng)。避免一次性增加很多突然超出上限。
網(wǎng)絡(luò)擁塞:增長(zhǎng)到一定程度,出現(xiàn)丟包,認(rèn)為當(dāng)前的窗口大小,已經(jīng)是傳輸?shù)臉O限了。
七、延遲應(yīng)答(效率機(jī)制)
TCP 可靠性的核心,是確認(rèn)應(yīng)答,ACK要發(fā),但是不是立即發(fā),而是稍微磨蹭一會(huì)再發(fā),TCP中決定傳輸效率的關(guān)鍵元素就是,窗口大小。
此時(shí)服務(wù)器并不會(huì)立即返回一個(gè)ACK,也不一定要等到服務(wù)器將緩沖區(qū)里的數(shù)據(jù)全部拿出來,等待一下,然后偷偷的拿數(shù)據(jù),悄悄的消耗緩沖區(qū)的數(shù)據(jù),這樣就相當(dāng)于增大了窗口的大小。然后等到合適的時(shí)機(jī)服務(wù)器在返回ACK應(yīng)答。
這樣使得窗口大小似乎變大了,然后效率相應(yīng)的變大了。
但是也并不是所有的報(bào)都延遲。
- 數(shù)量限制:每隔N個(gè)包就應(yīng)答一次;
- 時(shí)間限制:超過最大延遲時(shí)間就應(yīng)答一次;
八、捎帶應(yīng)答(效率機(jī)制)
是基于延遲應(yīng)答的。
適用于:客戶端,服務(wù)器,之間的通信模型,通常是“一問一答”這用模式
通信模型:
- 一問一答:絕大部分服務(wù)器都是這樣
- 多問一答:上傳大文件
- 一問多答:下載大文件
- 多問多答:游戲串流
原則是,客戶端發(fā)送一個(gè)消息,需要等待服務(wù)器的ACK,但是因?yàn)檠舆t等待,數(shù)據(jù)實(shí)際上已經(jīng)上傳了,并且也處理好了,按照一般邏輯就是,將處理好的數(shù)據(jù),返回給客戶端,之前 ACK 還沒有返回給客戶端,那么此時(shí) ACK 就會(huì)捎帶著服務(wù)器處理好的數(shù)據(jù)返回給客戶端。(原本分兩次的返回,現(xiàn)在一次就可以)
九、面向字節(jié)流(粘包問題)
這個(gè)有一個(gè)巨大的問題,就是粘包問題。
根據(jù)上面的說法綜合一下就知道,我們發(fā)送方傳輸?shù)臄?shù)據(jù),是多個(gè)數(shù)據(jù)放在一起傳輸?shù)?。然后在緩沖區(qū)上集結(jié)排列,然后接收方如何將數(shù)據(jù)分離,讀出一個(gè)完整的數(shù)據(jù)報(bào),此時(shí)造成的結(jié)果就是,容易讀出半個(gè)包,或者一個(gè)半的包,反正就是不是我們想要的。
如何解決?
提前約定好,數(shù)據(jù)的格式。比如:文章來源地址http://www.zghlxwxcb.cn/news/detail-702073.html
- 約定結(jié)尾符號(hào),接收方收到后,通過結(jié)尾符號(hào)知道一個(gè)完整的數(shù)據(jù)。
- 約定長(zhǎng)度,約定數(shù)據(jù)的前幾個(gè)字節(jié),表示整個(gè)數(shù)據(jù)包的長(zhǎng)度,通過光標(biāo)讀取字節(jié)長(zhǎng)度。讀取完整數(shù)據(jù)。
十、異常情況(心跳包)
- 進(jìn)程關(guān)閉 / 進(jìn)程崩潰
- 進(jìn)程沒有了,socket是文件,隨之關(guān)閉,雖然進(jìn)程沒有了,但是連接還在,仍然可以繼續(xù)關(guān)閉連接(四次揮手)
- 主機(jī)關(guān)機(jī)
- 先殺死所有的用戶進(jìn)程,也會(huì)觸發(fā)四次揮手,如果沒有揮完,比如 對(duì)方發(fā)了一個(gè)fin,咱們沒來得及 ack 就關(guān)機(jī)了,姿勢(shì)對(duì)端,就會(huì)重傳fin ,重傳幾次后,發(fā)現(xiàn)沒有 ACK ,嘗試重置連接,如果還不行,就直接釋放鏈接。
- 主機(jī)掉電
主機(jī)瞬間關(guān)閉,來不及任何揮手操作。
- 對(duì)方是發(fā)送方 :接收方收不到ACK =》超時(shí)重傳 =》重置鏈接 =》釋放鏈接
- 對(duì)方是接收方:發(fā)送方,沒辦法立即知道,接收方死機(jī)了,這邊還沒有來得及發(fā)新數(shù)據(jù),就沒了。
- TCP為了防止這種情況,內(nèi)置了一個(gè)機(jī)制,心跳機(jī)制(周期性的,如果沒有心跳,就代表掛了),也就是接收方會(huì)給發(fā)送方定期發(fā)一個(gè)心跳包(ping),然后發(fā)送方會(huì)給接收方發(fā)送一個(gè)返回(pong)
- 如果每個(gè)ping都有一個(gè)pong返回,就說明接收方是好的。如果bing了很多次,還沒反應(yīng),就知道就收方掛了。
- 網(wǎng)線斷開
- 同上,與主機(jī)掉電原理一樣
到了這里,關(guān)于網(wǎng)絡(luò)原理(二)TCP的可靠傳輸?shù)奈恼戮徒榻B完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!