Netty系列整體欄目
內(nèi)容 | 鏈接地址 |
---|---|
【一】深入理解網(wǎng)絡(luò)通信基本原理和tcp/ip協(xié)議 | https://zhenghuisheng.blog.csdn.net/article/details/136359640 |
【二】深入理解Socket本質(zhì)和BIO | https://zhenghuisheng.blog.csdn.net/article/details/136549478 |
一、計算機(jī)網(wǎng)絡(luò)體系
1,計算機(jī)網(wǎng)絡(luò)體系結(jié)構(gòu)
在最初的網(wǎng)絡(luò)中,是借鑒于這個OSI七層網(wǎng)絡(luò)模型,而在實際開發(fā)應(yīng)用中,更多的還是使用這個TCP/IP模型,分別是 物理層、數(shù)據(jù)鏈路層、網(wǎng)絡(luò)層、傳輸層、應(yīng)用層 ,相較于OSI模型,TCP/IP模型是將會話層和表示層都結(jié)合到了應(yīng)用層里面
TCP的縮寫是 Transmission Controller Protocol ,看到第一個單詞傳輸,因此得知這個TCP是在這個傳輸層的;IP的縮寫是 Internet Protocol ,該協(xié)議是位于網(wǎng)絡(luò)層的,中文將這兩個名字稱為是 傳輸控制協(xié)議/英特網(wǎng)互聯(lián)協(xié)議 。如下圖,應(yīng)用層中有HTTP,Telnet、DNS等協(xié)議;傳輸層中包含TCP、UDP協(xié)議;網(wǎng)絡(luò)層中包含 IP、ICMP等協(xié)議;鏈路層中包含PDN、PPP等協(xié)議
在應(yīng)用中,還是TCP、UDP和IP這三者使用的范圍最廣。
-
ip用于確定是哪臺主機(jī),有點類似于電話號碼,確定能打到那個人身上
-
TCP是一個可靠連接的一個協(xié)議,需要通過三次握手建立連接,有點類似于兩臺電話,必須接通才能通話。絕大多數(shù)場景下還是通過tcp協(xié)議完成的,因為該協(xié)議相對穩(wěn)定可靠,需要等建立連接之后才能傳輸數(shù)據(jù),并且在傳輸數(shù)據(jù)時可以通過一定的限流方式進(jìn)行流量控制,從而保證數(shù)據(jù)傳輸?shù)目煽啃浴?/p>
-
UDP是一個面向無連接的協(xié)議,類似于商家和快遞,商家不關(guān)心用戶能不能接收到,不需要和用戶建立直接關(guān)系。如在實際開發(fā)中,視頻語言等都是通過UDP實現(xiàn)的,允許部分?jǐn)?shù)據(jù)丟失。如虎牙斗魚這些,有對應(yīng)的清晰度,通過不同的清晰度,決定每次傳輸數(shù)據(jù)的大小,清晰度越小,即使丟包也是允許的
2,網(wǎng)絡(luò)中數(shù)據(jù)傳輸
2.1,瀏覽器中輸入一個url的執(zhí)行流程
url:被稱為統(tǒng)一資源定位符,一個完整的url,都會包含這四部分,分別是協(xié)議、域名、路徑和資源。當(dāng)在瀏覽器中輸入一個url時,如在瀏覽器中輸入www.baidu.com,其內(nèi)部會執(zhí)行的流程如下:
- 首先是域名解析,就是將網(wǎng)址解析成具體的ip。如果不是第一次訪問這個網(wǎng)址,那么正常會在host文件中保存對應(yīng)的ip,那么就可以直接通過本地的host文件解析;如果是第一次訪問這個網(wǎng)址,那么本地host文件中不存在,就需要去本地的DNS服務(wù)器查找,沒有再去root根DNS服務(wù)器中獲取
- 再獲取到這個具體的ip之后,通過三次握手的方式,與對方建立TCP的可靠連接
- 建立連接成功之后,再向服務(wù)器發(fā)送一個http的請求
- 服務(wù)器接收到請求之后,服務(wù)器會處理相關(guān)請求
- 隨后服務(wù)器會將響應(yīng)結(jié)果返回給客戶端
- 隨后通過四次揮手?jǐn)嚅_連接
- 瀏覽器接收到響應(yīng)之后,對響應(yīng)的內(nèi)容進(jìn)行解析
- 瀏覽器將解析的內(nèi)容渲染,如css,js等,最后進(jìn)行布局展示
2.2,數(shù)據(jù)在網(wǎng)絡(luò)中是的傳輸流程
在網(wǎng)絡(luò)通信中,客戶端A需要向客戶端B發(fā)送數(shù)據(jù),也是需要通過tcp/ip 五層協(xié)議的,如下圖,如主機(jī)A向主機(jī)B中發(fā)送一條數(shù)據(jù)
主機(jī)A發(fā)送數(shù)據(jù)的流程
- 首先數(shù)據(jù)會先經(jīng)過應(yīng)用層,然后攜帶一個應(yīng)用層的頭部,此時為數(shù)據(jù)包
- 隨后繼續(xù)經(jīng)過傳輸層,由于是TCP協(xié)議,因此繼續(xù)攜帶一個TCP的頭部,此時為數(shù)據(jù)段
- 隨后繼續(xù)經(jīng)過ip層,因此繼續(xù)攜帶一個IP層的頭部,此時為數(shù)據(jù)報
- 隨后到達(dá)鏈路層,最后將數(shù)據(jù)封裝成以太網(wǎng)數(shù)據(jù)幀,隨后通過以太網(wǎng)電纜傳輸?shù)侥繕?biāo)ip
主機(jī)B接收數(shù)據(jù)的流程
- 在通過電纜接收到數(shù)據(jù)之后,會先經(jīng)過數(shù)據(jù)鏈路層層層解析,從下往上依次解析,先經(jīng)過鏈路層,隨后網(wǎng)絡(luò)層,隨后傳輸層,再到應(yīng)用層,全部解析完成之后,再返回給客戶端
3,三次握手和四次揮手
3.1,三次握手
在tcp建立連接時,需要通過三次握手來實現(xiàn)連接,從而實現(xiàn)這種穩(wěn)定可靠性,其流程如下
- 首先客戶端會向服務(wù)端發(fā)送一個SYN=1的一個報文標(biāo)志,并且設(shè)置一個seq_no的字段值為10000,此時客戶端進(jìn)入一個 SYN_SENT 的狀態(tài)
- 服務(wù)端在接收到這個請求之后,會對客戶端進(jìn)行一個響應(yīng),也會發(fā)送一個SYN=1的報文,并且設(shè)置一個ACK=1的標(biāo)志位,同時會返回一個ack_no回應(yīng)客戶端的seq_no,值為客戶端seq_no的值+1,最后還會設(shè)置一個seq_no的值,其值為30000。此時服務(wù)端進(jìn)入一個SYN_REVD的狀態(tài)
- 客戶端在接收到服務(wù)端的響應(yīng)之后,客戶端需要給服務(wù)端一個響應(yīng),告訴服務(wù)端客戶端接收到這個響應(yīng)了。會繼續(xù)返回一個SYN=1的報文,并且只需要返回一個ack_no,其值為服務(wù)端seq_no的值+1,最后服務(wù)端和客戶端的狀態(tài)都變?yōu)?ESTABLEISHED 連接建立的狀態(tài)
三次握手主要的原因是為了建立可靠連接,在連接過程中,客戶端的seq序列號需要服務(wù)端的ack序列號應(yīng)答,服務(wù)端的seq序列號也需要客戶端的ack序列號應(yīng)答保證可靠性,如出現(xiàn)丟包重傳的的話,那么可以直接根據(jù)具體的seq序列號進(jìn)行重傳即可。主要是通過超時重傳機(jī)制 和 應(yīng)答確認(rèn)機(jī)制 來保證可靠傳。
最后一次握手是為了告知服務(wù)端,客戶端確實收到了服務(wù)端的響應(yīng),對于響應(yīng)syn_no的seq_no的值,至于要加多少,取決于接收了多個包,即取決于SYN的值的大小,如果接收了3個包,且seq_no的值為10000,那么響應(yīng)的ack_no的值則為10003
3.1.1,洪范攻擊
SYN洪范攻擊的定義如下:就是通過網(wǎng)絡(luò)所在的端口發(fā)送大量偽造原地址的攻擊報文發(fā)送到服務(wù)端,造成服務(wù)端上面的半開連接隊列被占滿,從而阻止其他用戶進(jìn)行訪問。
在三次握手中,也存在一定的缺陷,有可能會出現(xiàn)這個SYN洪范攻擊 ,就是利用偽造的ip地址向服務(wù)端發(fā)出第一次握手,而tcp連接為了維護(hù)三次握手,就會響應(yīng)這個偽造ip的請求,然而服務(wù)端這邊一直在等客戶端的響應(yīng),即第三次握手,如果偽造服務(wù)端一直不響應(yīng),隨著偽造ip請求的增多,那么服務(wù)端的資源會被耗盡。該方式屬于一種ddos的攻擊,可以通過加防火墻等避免,設(shè)置定時任務(wù)去移除無法響應(yīng)的請求。
在三次握手中,會存在大量的客戶端去連接服務(wù)端,服務(wù)端會將不能及時響應(yīng)的客戶端的請求,先存放在一個隊列中。那么洪范攻擊就會利用這個特性,從客戶端發(fā)送一個偽造的數(shù)據(jù)報文到服務(wù)端,服務(wù)器會為了保證三次握手,就會對這個偽造數(shù)據(jù)的服務(wù)器做出響應(yīng),由于攻擊者的ip是偽造的,那么服務(wù)器這邊的響應(yīng)就一直到達(dá)不了偽造者客戶端的ip,并且接收不到客戶端的第三次響應(yīng),導(dǎo)致該次連接一直不被釋放。那么偽造多個ip去請求服務(wù)端的話,那么會造成大量的連接處于不被釋放狀態(tài),從而讓這個隊列占滿,導(dǎo)致整個服務(wù)器處于癱瘓的狀態(tài)。
解決這個洪泛攻擊的方案如下:
- 無效連接監(jiān)控釋放:就是給一個監(jiān)聽事件,對隊列中要響應(yīng)的請求進(jìn)行監(jiān)聽,如果在一定的時間內(nèi)還沒有成功的建立三次握手,那么就可以直接將該次請求釋放清理掉
- 延緩TCP分配方法: 就是在分配tcp的時候,在三次握手建立成功之后,再來分配tcp
- 開啟防火墻: 通過防火墻來確認(rèn)這個客戶端ip地址的有效性,只有這個ip地址是有效的才與客戶端建立連接
3.1.2,為什么需要三次握手
上面講解了三次握手的過程以及三次握手的缺陷,然而在tcp協(xié)議中,為什么建立連接需要三次握手呢,其主要原因如下:在建立連接過程中雙方都會發(fā)送一個序列號,這樣就可以知道發(fā)送報文的起始的序列號和最終的序列號,從而通過序列號的值知道有哪些報文,通過差值確認(rèn)報文的個數(shù),當(dāng)服務(wù)端接收的報文的個數(shù)小于差值時,就通過序列號確定哪個報文被丟失,就會進(jìn)行重傳的操作,從而來保證該協(xié)議的可靠性
如在服務(wù)端給客戶端發(fā)送建立連接時,seq_no的值設(shè)置成10000,SYN的值設(shè)置成3,但是服務(wù)端這邊返回ack_no的值為10002,此時差值為2表示只收到兩個數(shù)據(jù)包,但是SYN的值為3表示發(fā)送了3個數(shù)據(jù)包,故而得知少了一個服務(wù)端少接收了一個數(shù)據(jù)包,那么服務(wù)端這邊就會進(jìn)行重發(fā)的操作。服務(wù)端響應(yīng)客戶端也會發(fā)一個seq_no的序列號給客戶端,然后客戶端回應(yīng)服務(wù)端一個ack_no,其本質(zhì)也是一樣,通過差值和SYN的值進(jìn)行比較,查看是否出現(xiàn)丟包的情況。
3.2,四次揮手
當(dāng)tcp連接斷開時,其底層也是通過四次揮手的方式來斷開連接。與建立連接的三次握手不一樣,三次握手是固定的從客戶端發(fā)起握手的請求,但是四次揮手不一樣,揮手是客戶端和服務(wù)端都可以發(fā)起斷開連接的請求。四次揮手的流程如下(以客戶端發(fā)起斷開請求為例)
- 首先客戶端發(fā)起斷開連接的請求,此時會向服務(wù)端發(fā)送一個FIN的標(biāo)志,并且會設(shè)置序列號seq_no,假設(shè)此時FIN的值為,seq_no的值為8888,此時客戶端處于FIN_WAIT_1的狀態(tài)
- 服務(wù)端接收到請求之后,服務(wù)端會先響應(yīng)一個接收到該請求的響應(yīng),會往服務(wù)端發(fā)送一個ACK確認(rèn)的標(biāo)志,同時返回一個ack_no的值,改值為接收到的序列號+FIN傳過來的包的數(shù)量,如此時為8889,此時服務(wù)端處于close_wait的狀態(tài)
- 一段時間之后,服務(wù)端會向客戶端再次發(fā)送一次報文,也會設(shè)置一個FIN的值和一個seq_no的值,如設(shè)置一個FIN=1,seq_no = 8890,此時服務(wù)器端會處于LAST_WAIT的狀態(tài),
- 客戶端在收到服務(wù)端發(fā)送的第二次報文之后,會再向服務(wù)端發(fā)送一個報文,設(shè)置ACK=1的確認(rèn)標(biāo)志,并且設(shè)置一個ack_no=8891的值,此時客戶端處于TIME_WAITING的狀態(tài),最后服務(wù)端接收到響應(yīng)報文之后,服務(wù)端會處于一個CLOSED的狀態(tài)
3.2.1,為什么需要time-wait
在上圖中可知,在客戶端第二次向服務(wù)端發(fā)送報文的時候,會有一個TIME-WAIT的時間設(shè)置,規(guī)定需要等待2MSL,一般的操作系統(tǒng)都是設(shè)置成2分鐘,當(dāng)然會有部分的操作系統(tǒng)設(shè)置的值不一樣,如在linux操作系統(tǒng)設(shè)置的值為1分鐘,那么接下來需要了解,為什么這段第四次揮手需要等待兩分鐘
- 首先還是為了保證系統(tǒng)的可靠性,如服務(wù)端第二次給客戶端報文時設(shè)置的seq是2000,F(xiàn)IN=4,此時是有4個包,但是客戶端接收到的seq的值為2002,正常是2004,少了兩個包,此時就需要服務(wù)端重傳
- 第二個原因是如果不設(shè)置那么長時間,往服務(wù)端發(fā)送完數(shù)據(jù)之后直接closed,那么就會出現(xiàn)一個問題,如果此時服務(wù)端發(fā)現(xiàn)客戶端seq的值少了兩個,需要服務(wù)端這邊重傳,然后客戶端這邊已經(jīng)關(guān)閉連接,如果此時是還是剛剛關(guān)閉的客戶端發(fā)起的一個新的程序,并且此時的客戶端的操作系統(tǒng)又給這個新的應(yīng)用程序分配的就是上一個端口號,那么此時新的應(yīng)用程序就會拿到一個上一個服務(wù)端第三次揮手重傳的數(shù)據(jù),此時新的應(yīng)用程序就會處于一個懵圈狀態(tài),此時就會出現(xiàn)一個報文混亂的狀態(tài)。為了保證tcp傳輸?shù)目煽啃?,因此需要在這里做一個時間等待
確認(rèn)一個連接就是源ip,源端口號,目標(biāo)ip,目標(biāo)端口號,上面第二點的第三次握手的報文還是發(fā)送在同一個ip的同一個端口號,因此還是同一個連接,那么新的應(yīng)用程序就會接收到上一個關(guān)閉程序的報文
3.2.2,time-wait舉例
上面講了為什么需要time-wait,這里舉一個在實際開發(fā)中,可能出現(xiàn)time-wait的案例。
以mysql為例,假設(shè)在實際開發(fā)中,用完mysql之后沒有主動的去closed,如果客戶端長時間的沒有向服務(wù)端發(fā)送數(shù)據(jù)報文,發(fā)么mysql服務(wù)端可能就會認(rèn)為該客戶端已經(jīng)下線,那么服務(wù)端就發(fā)起斷開連接的操作,此時由服務(wù)端發(fā)起第一次揮手,服務(wù)端第四次揮手響應(yīng)客戶端之后,會有一個TIME_WAIT的等待時間,假設(shè)該操作系統(tǒng)的time-wait是2分鐘,那么需要再2分鐘之后,服務(wù)端才會closed,才能真正的去釋放一個連接
如果每次用完mysql都不主動的去closed,那么每次都會由服務(wù)端去發(fā)起斷開連接的請求,就會產(chǎn)生大量的time-wait,服務(wù)器會隨著客戶端的不斷增加,在某一個時間點會出現(xiàn)資源耗盡的情況,如果是一臺繁忙的服務(wù)器,那么就很有可能因為這個time-wait出現(xiàn)宕機(jī)的情況。
因此在實際開發(fā)中,如果是手動的通過JDBC驅(qū)動實現(xiàn)mysql的連接,那么一定要記得手動的close,讓客戶端去發(fā)起斷開連接的請求,讓time-wait這個時間結(jié)點出現(xiàn)在客戶端這邊,減少服務(wù)端這邊的資源損耗。
4,UDP協(xié)議
udp和tcp都是處于傳輸層,但是udp和tcp底層實現(xiàn)不一樣,udp屬于不可靠連接,面向的是無連接的協(xié)議,就是說客戶端發(fā)送數(shù)據(jù)之后,不需要去關(guān)心服務(wù)端是否收到數(shù)據(jù),udp的特性如下
-
因為udp在一端發(fā)送數(shù)據(jù)之后不需要關(guān)心另一端是否收到數(shù)據(jù),因此udp會出現(xiàn)丟包的情況
-
也因為不需要對端接收數(shù)據(jù)的確認(rèn),因此udp的速度快于tcp
-
udp雙端屬于點對點連接,因此可以通過udp實現(xiàn)udp單播
-
udp也可以不設(shè)置另一端的端口號,那么可以通過udp實現(xiàn)廣播,可以讓多個端口號接收到數(shù)據(jù)文章來源:http://www.zghlxwxcb.cn/news/detail-840738.html
-
由于允許丟包這種,那么視頻音頻這些都可以通過udp的方式實現(xiàn)通信文章來源地址http://www.zghlxwxcb.cn/news/detail-840738.html
到了這里,關(guān)于【netty系列-01】深入理解網(wǎng)絡(luò)通信基本原理和tcp/ip協(xié)議的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!