OSI模型——傳輸層
運輸層
運輸層概述
運輸層提供應用層端到端通信服務,通俗的講,兩個主機通訊,也就是應用層上的進程之間的通信,也就是轉換為進程和進程之間的通信了,我們之前學到網絡層,IP協議能將分組准確的發送到目的主機,但是停留在網絡層,並不知道要怎么交給我們的主機應用進程,通過前面的學習,我們學習有mac地址,通過mac地址能找到同一個網絡下主機,有IP地址,通過ip地址能找到不同網絡下的網絡,結合mac地址就能找到對應主機,那么怎么找到主機應用進程呢,肯定也有一個東西來標識它,那就是我們常說的端口了。
端口
占有16位,其大小也就有65536個,是從0~65535.也就是一台計算機有65535個端口,主機之間的通訊,也就是應用進程之間的通訊,都要依靠端口,一個進程對應一個端口,進程A和進程B通信,進程A分到的端口為60000,進程B分到的端口為60001,進程A通過端口60000發送數據給進程B,就知道要交給60001端口,也就到了進程B中,這樣就達到了通信的目的。
熟知端口、登記端口、客戶端端口
- 熟知端口:0-1023, 也就是一些固定的端口號,比如http使用的80端口,意思就是在訪問網址時,我們訪問服務器的端口就是80,然后服務器那邊傳網頁的數據給我們。
- 登記端口:1024-49151,比如微軟開發了一個系統應用,該應用在通訊或使用時,需要使用到xxx端口,那么就要去登記一下這個端口,以免有別人公司的應用使用同一個端口號,例如,windows系統中的3389端口,就是用來實現遠程連接的,就固定了這台計算機如果要使用遠程連接服務,就打開3389端口,別人就能使用遠程連接連你了,默認是不打開的。
- 客戶端端口:49152-65535,一般我們使用某個軟件,比如QQ,等其他服務,隨機拿這個范圍內的端口,而不是去拿前面哪些固定的,拿到等通訊結束后,就會釋放該端口。
運輸層就是將兩個端口連起來通信的介質,不然光知道兩個端口有什么用,怎么通信的,還是要靠運輸層來做這個事情,其中重要的就是靠兩個協議,UDP和TCP協議。
UDP協議
UDP:User Datagram Protocol 用戶數據報協議,無連接、不可靠
- 無連接:意思就是在通訊之前不需要建立確定連接,直接傳輸數據。
- 不可靠:是將數據報的分組從一台主機發送到另一台主機,但並不保證數據報能夠到達另一端,任何必須的可靠性都由應用程序提供。在 UDP情況下,雖然可以確保發送消息的大小,卻不能保證消息一定會達到目的端。沒有超時和重傳功能,當 UDP 數據封裝到 IP 數據報傳輸時,如果丟失,會發送一個 ICMP差錯報文給源主機。即使出現網絡阻塞情況,UDP也無法進行流量控制。此外,傳輸途中即使出現丟包,UDP 也不負責重發,甚至當出現包的到達順序雜亂也沒有糾正的功能。
UDP的首部格式
UDP首部
- 源端口號:占16位,源主機的應用進程所使用的端口號
- 目標端口號:占16位,目標主機的應用進程所使用的端口號,也就是我們需要通信的目標進程
- UDP報長度:UDP用戶數據報的長度,數據部分+UDP首部之和為UDP報長度。
- 檢驗和:檢驗和是為了提供可靠的 UDP首部和數據而設計,這里不要和上面的不可靠傳輸搞混淆了,這里提供可靠的UDP首部,是因為一個進程可能接受多個進程過來的報文,那么如何區分他們呢,就是通過5個東西來進行區分的, “源IP地址”、“目的IP地址”、“協議號”、“源端口號”、“目標端口號”的,這個檢測可靠,是檢測接受哪個正確的報文,也就是說是哪個報文要進這個端口,那個不可靠,說的是這個報文可能丟失,可能其中數據損壞了我們不關心,但是這些的前提是,你得傳輸到正確的目的地去。
UDP偽首部
就是拿到IP層的一些數據,因為要進行檢驗和,就必須要有這些數據。其中檢驗的算法跟IP層中檢驗首部的辦法是一樣的。
一個目標進程中,其中的報文,目標端口,目標ip地址肯定都一樣的,但是源IP地址和源端口就可能不一樣,這就說明了不同源而同一目的地的報文會定位到同一隊列。這跟接下來我們要討論的TCP不一樣,因為UDP是無連接的,大家都是用這一條通道,所以其隊列中就會出現上面所說的這樣的情況。
使用UDP協議的例子:
- 應用層協議中DNS,也就是根據域名解析ip地址的一個協議,他使用的就是UDP
- DHCP,這個是給各電腦分配ip地址的協議,其中用的也是UDP協議
- IGMP,我們說的多播,也就是使用的UDP,在多媒體教師,老師拿筆記本講課,我們在下面通過各自的電腦看到老師的畫面,這就是通過UDP傳輸數據,所以會出現有的同學卡,有的同學很流暢,就是因為其不可靠傳輸,但是卡一下,對接下來的觀看並沒有什么影響
TCP協議
TCP協議是面向連接的、可靠傳輸、有流量控制,擁塞控制,面向字節流傳輸等很多優點的協議。其最終功能和UDP一樣,在端和端之間進行通信,但是和UDP的區別還是很大的。
TCP報文的結構
- 源端口號
- 目標端口號
- 序列號:因為在TCP是面向字節流的,他會將報文度分成一個個字節,給每個字節進行序號編寫,比如一個報文有900個字節組成,那么就會編成1-900個序號,然后分幾部分來進行傳輸,比如第一次傳,序列號就是1,傳了50個字節,那么第二次傳,序列號就為51,所以序列號就是傳輸的數據的第一個字節相對所有的字節的位置。
- 確認應答:如剛說的例子,第一次傳了50個字節給對方,對方也會回應你,其中帶有確認應答,就是告訴你下一次要傳第51個字節來了,所以這個確認應答就是告訴對方要傳第多少個字節了
- 首部長度:就是首部的長度
- 保留:給以后有需要在用,這個保留的位置放的東西是跟控制位類似的
- 控制位:目前有的控制位為6個
- URG:緊急,當URG為1時,表名緊急指針字段有效,標識該報文是一個緊急報文,傳送到目標主機后,不用排隊,應該讓該報文盡量往下排,讓其早點讓應用程序給接受。
- ACK:確認,當ACK為1時,確認序號才有效。當ACK為0時,確認序號沒用
- PSH:推送,當為1時,當遇到此報文時,會減少數據向上交付,本來想應用進程交付數據是要等到一定的緩存大小才發送的,但是遇到它,就不用在等足夠多的數據才向上交付,而是讓應用進程早點拿到此報文,這個要和緊急分清楚,緊急是插隊,但是提交緩存大小的數據不變,這個推送就要排隊,但是遇到他的時候,會減少交付的緩存數據,提前交付。
- RST:復位,報文遇到很嚴重的差錯時,比如TCP連接出錯等,會將RST置為1,然后釋放連接,全部重新來過。
- SYN:同步,在進行連接的時候,也就是三次握手時用得到,下面會具體講到,配合ACK一起使用
- FIN:終止,在釋放連接時,也就是四次揮手時用的。
- 窗口:指發送報文段一方的接受窗口大小,用來控制對方發送的數據量(從確認號開始,允許對方發送的數據量)。也就是后面需要講的滑動窗口的窗口大小
- 檢驗和:檢驗首部和數據這兩部分,和UDP一樣,需要拿到偽首部中的數據來幫助檢測
- 選項:長度可變,介紹一種選項,最大報文段長度,MSS。能夠告訴對方TCP,我的緩存能接受報文段的數據字段的最大長度是MSS個字節。如果沒有使用選項,那么首部固定是20個字節
- 填充:就是為了讓其成為整數個字節
面向連接
(三次握手):在通信之前,會先通過三次握手的機制來確認兩端口之間的連接是否可用。而UDP不需要確認是否可用,直接傳。
三次握手機制
- 一開始客戶端和服務端都市關閉狀態,但是在某個時刻,客戶端需要和服務端進行通信,此時雙方都會各自准備好端口,服務器段的端口會處於監聽狀態,等待客戶端的連接。客戶端可會知道自己的端口號,和目的進程的端口號,這樣才能發起請求。
- 第一次握手:客戶端想與服務器進行連接了,所以狀態變為主動打開,同時發送一個連接請求報文給服務器段SYN=1,並且會攜帶x個字節過去。發送完請求連接報文后,客戶端的狀態就變為了SYN_SENT,可以說這個狀態是等待發送確認(為了發送第三次握手時的確認包)
- 第二次握手:服務端接收到連接請求報文后,從LSTTEN狀態變為被動打開狀態,然后給客戶端返回一個報文。這個報文有兩層意思,一是確認報文,而可以達到告訴客戶端,我也打開連接了。發完后,變為SYN_RCVD狀態(也可以說是等待接受確認狀態,接受客戶端發過來的確認包)
- 第三次握手:客戶端得到服務器端的確認和知道服務器端也已經准備好了連接后,還會發一個確認報文到服務器端,告訴服務器端,我接到了你發送的報文,接下來就讓我們兩個進行連接了。客戶端發送完確認報文后,進入ESTABLISHED,而服務器接到了,也變為ESTABLISHED,進入到ESTABLISHED狀態后,連接就已經完成了,可以進行通信了。
問題:為什么需要第三次握手,有前面兩次不就已經可以了嗎?
假設沒有第三次握手,客戶端發送一個連接請求報文過去,但是因為網絡延遲,在等待了一個超時時間后,客戶端就會在重新發一個請求連接報文過去,然后正常的進行,服務器端發回一個確認連接報文,然后就開始通訊,通訊結束后,那個第一次因為網絡延遲的請求連接報文到了服務器端,服務器端不知道這個報文已經失效,也發回了一個確認連接報文,客戶端接收后,發現自己並沒有發送連接請求(因為超時了,所以就認為自己沒有發),所以對這個確認連接請求就什么也不做,但是此時客戶端不這么認為,他認為i連接已經建立了,就一直打開着等待客戶端傳數據過來,這就造成了極大的浪費。如果有了第三次握手,那么客戶端就可以通知服務器了。所以第三次握手也很重要。
同時打開連接請求
正常情況下,通信一方請求建立連接,另一方響應該請求,但是如果出現,通信雙方同時請求建立連接時,則連接建立過程並不是三次握手過程,而且這種情況的連接也只有一條,並不會建立兩條連接。同時打開連接時,兩邊幾乎同時發送 SYN,並進入 SYN_SENT狀態,當每一端收到 SYN 時,狀態變為 SYN_RCVD,同時雙方都再發 SYN 和 ACK 作為對收到的 SYN 進行確認應答。當雙方都收到 SYN 及相應的 ACK 時,狀態變為 ESTABLISHED
-
可靠傳輸
通過數據編號和積累確認、以字節為單位的滑動窗口、超時重傳時間 、快速重傳這四個方面來達到可靠傳輸的目的。- 數據編號:將每個字節進行編號,有900個字節,就從1到900進行編號
- 積累確認:服務器端不是接收到一個字節就發一個確認,那樣效率太低,而是當接收到4,5個時,在發送一個確認,那么在之前的確認之前的數據就算發送成功了的。
- 滑動窗口:這個跟在數據鏈路層講個滑動窗口一樣。每次能發送的數據是在此窗口中的,接到了多少數據,就往后滑多少數據
- 超時重傳時間:這個也在鏈路層講過,如果等待一段時間后,還沒接收到確認報文,那么就重新傳
- 快速重傳:在滑動窗口中的應用,比如傳了12346到服務器端,老辦法是在4之后的所有數據度要重新傳,而這個快速重傳就只需要等待傳了5這個序號,就可以繼續往下接收數據了。
-
流量控制
在傳輸層中,有接受緩存和發送緩存這兩個東西的存在,所以每次發送數據過去另一端時,都會把這些數據給帶過去,讓對方知道自己的這兩個緩存的大小,然后來合理的設置自己的發送窗口的大小,如果對方的緩存快滿了,對方在傳送數據過來的時候,就會告訴自己,少發一點數據過來,自己就設置滑動窗口小一點,讓對方有緩沖的機會,而不會導致緩存溢出,不讓自己的報文被丟棄。 -
擁塞控制
其實跟流量控制差不多,但是站的角度更大,此時既考慮了對方接收不過來,緩存太多溢出導致,又考慮在線路中,線路上的傳輸速率就那么大,但是有很多人同時用,發送的數據太多,就會使線路發現擁塞,也就是路由器可能轉發不過來,導致大量數據丟失,這兩個問題。所以擁塞控制這個解決方案,大概意思就是當檢測到有網絡擁塞時,就會讓自己的滑動窗口變小,但具體是怎么變化的,就是根據算法來算了,發送窗口的上限值 = Min[rwnd,cwnd]- rwnd:接受窗口,根據接受緩存,而定的接受窗口,接收緩存還有很多,那么接收窗口就大
- cwnd:擁塞窗口,根據線路中的擁塞狀況來決定,線路中不擁塞,那么此窗口就大,
發送窗口是取兩個中較小值。這個還是可以理解的。慢啟動算法、快速恢復算法、結合來達到對擁塞進行控制的
TCP釋放連接時的四次揮手
- 第一次揮手:從ESTABLISHED變為主動關閉狀態,客戶端主動發送釋放連接請求給服務器端,FIN=1。發送完之后就變為FIN_WAIT_1狀態,這個狀態可以說是等待確認狀態。
- 第二次揮手:服務器接收到客戶端發來的釋放連接請求后,狀態變為CLOSE_WAIT,然后發送確認報文給客戶端,告訴他我接收到了你的請求。為什么變為CLOSE_WAIT,原因是是客戶端發送的釋放連接請求,可能自己這端還有數據沒有發送完呢,所以這個時候整個TCP連接的狀態就變為了半關閉狀態。服務器端還能發送數據,並且客戶端也能接收數據,但是客戶端不能在發送數據了,只能夠發送確認報文。客戶端接到服務器的確認報文后,就進入了FIN_WAIT_2
狀態。也可以說這是等待服務器釋放連接狀態。 - 第三次揮手:服務器端所有的數據度發送完了,認為可以關閉連接了,狀態變為被動關閉,所以向客戶端發送釋放連接報文,發完之后自己變為LAST_WAIT狀態,也就是等待客戶端確認狀態
- 第四次揮手:客戶端接到釋放連接報文后,發送一個確認報文,然后自己變為TIME_WAIT,而不是立馬關閉,因為客戶端發送的確認報文可能會丟失,丟失的話服務器就會重傳一個FIN,也就是釋放連接報文,這個時候客戶端必須還沒關閉。當服務器接受到確認報文后,服務器就進入CLOSE狀態,也就是關閉了。但是由於上面說的這個原因,客戶端必須等待一定的時間才能夠進入CLOSE狀態。
同時關閉連接
正常情況下,通信一方請求連接關閉,另一方響應連接關閉請求,並且被動關閉連接。但是若出現同時關閉連接請求時,通信雙方均從 ESTABLISHED 狀態轉換為 FIN_WAIT_1狀態。任意一方收到對方發來的 FIN 報文段后,其狀態均由 FIN_WAIT_1轉變到 CLOSING 狀態,並發送最后的 ACK 數據段。當收到最后的ACK數據段后,狀態轉變化TIME_WAIT,在等待 2MSL 時間后進入到 CLOSED 狀態,最終釋放整個TCP傳輸連接。