TCP的三次握手和四次揮手
三次握手
TCP連接是通過三次握手來連接的。
第一次握手
當客戶端向服務器發起連接請求時,客戶端會發送同步序列標號SYN
到服務器,在這里我們設SYN
為x,等待服務器確認,這時客戶端的狀態為SYN_SENT
。
第二次握手
當服務器收到客戶端發送的SYN
后,服務器要做的是確認客戶端發送過來的SYN
,在這里服務器發送確認包ACK
,這里的ACK
為x+1,意思是說“我收到了你發送的SYN
了”,同時,服務器也會向客戶端發送一個SYN
包,這里我們設SYN
為y。這時服務器的狀態為SYN_RECV
。
一句話,服務器端發送SYN
和ACK
兩個包。
第三次握手
客戶端收到服務器發送的SYN
和ACK
包后,需向服務器發送確認包ACK
,“我也收到你發送的SYN
了,我這就給你發個確認過去,然后我們即能合體了”,這里的ACK
為y+1,發送完畢后,客戶端和服務器的狀態為ESTABLISH
,即TCP連接成功。
在三次握手中,客戶端和服務器端都發送兩個包SYN
和ACK
,只不過服務器端的兩個包是一次性發過來的,客戶端的兩個包是分兩次發送的。
四次揮手
當A端和B端要斷開連接時,需要四次握手,這里稱為四次揮手。
斷開連接請求可以由客戶端發出,也可以由服務器端發出,在這里我們稱A端向B端請求斷開連接。
第一次揮手
A端向B端請求斷開連接時會向B端發送一個帶有FIN
標記的報文段,這里的FIN
是Finish
的意思。
第二次揮手
B端收到A發送的FIN
后,B段現在可能現在還有數據沒有傳完,所以B端並不會馬上向A端發送FIN
,而是先發送一個確認序號ACK
,意思是說“你發的斷開連接請求我收到了,但是我現在還有數據沒有發完,請稍等一下唄”。
第三次揮手
當B端的事情忙完了,那么此時B端就可以斷開連接了,此時B端向A端發送FIN
序號,意思是這次可以斷開連接了。
第四次揮手
A端收到B端發送的FIN
后,會向B端發送確認ACK
,然后經過兩個MSL時長后斷開連接。
MSL是Maximum Segment Lifetime,最大報文段生存時間,2個MSL是報文段發送和接收的最長時間。
兩次握手可以么?
TCP連接時是三次握手,那么兩次握手可行嗎?
在謝希仁著《計算機網絡》第六版中講"三次握手"的目的是"為了防止已失效的連接請求報文段突然又傳送到了服務端,因而產生錯誤"。
假定出現一種異常情況下:client發出的第一個連接請求報文段並沒有丟失,而是在某個網絡結點長時間的滯留了,以致延誤到連接釋放以后的某個時間才到達server。本來這是一個早已失效的報文段。但server收到此失效的連接請求報文段后,就誤認為是client再次發出的一個新的連接請求。於是就向client發出確認報文段,同意建立連接。假設不采用“三次握手”,那么只要server發出確認,新的連接就建立了。由於現在client並沒有發出建立連接的請求,因此不會理睬server的確認,也不會向server發送ACK
包。這樣就會白白浪費資源。
而經過三次握手,客戶端和服務器都有應有答,這樣可以確保TCP正確連接。
為什么TCP連接是三次,揮手確是四次?
在TCP連接中,服務器端的SYN
和ACK
向客戶端發送是一次性發送的,而在斷開連接的過程中,B端向A端發送的ACK
和FIN
是是分兩次發送的。因為在B端接收到A端的FIN
后,B端可能還有數據要傳輸,所以先發送ACK
,等B端處理完自己的事情后就可以發送FIN
斷開連接了。
為什么在第四次揮手后會有2個MSL的延時?
前文說到:
MSL是Maximum Segment Lifetime,最大報文段生存時間,2個MSL是報文段發送和接收的最長時間。
假定網絡不可靠,那么第四次發送的ACK
可能丟失,即B端無法收到這個ACK
,如果B端收不到這個確認ACK
,B端會定時向A端重復發送FIN
,直到B端收到A的確認ACK
。所以這個2MSL就是用來處理這個可能丟失的ACK
的。
TCP流量控制
一般說來,我們總是希望數據傳輸得更快一些。但如果發送方把數據發送得過快,接收方可能來不及接收,這就會造成數據的丟失。所謂 流量控制(flow contrl) 就是 讓發送方的發送速率不要太快,要讓接收方來得及接收 。
TCP利用滑動窗口機制實現對發送方的流量控制,發送方的發送窗口不可以大於接收方給出的接收窗口的大小。窗口兩個邊沿的相對運動增加或減少了窗口的大小。當接收方沒有緩存可用,會發送零窗口大小的報文,此時發送方不能夠發送任何數據。
TCP的窗口單位是字節,不是報文段。
滑動窗口
滑動窗口協議是傳輸層進行流控的一種措施,接收方通過通告發送方自己的窗口大小,從而控制發送方的發送速度,從而達到防止發送方發送速度過快而導致自己被淹沒的目的。
TCP滑動窗口分為接受窗口,發送窗口。
對ACK的再認識,ack通常被理解為收到數據后給出的一個確認ACK,ACK包含兩個非常重要的信息:
- 期望接收到的下一字節的序號n,該n代表接收方已經接收到了前n-1字節數據,此時如果接收方收到第n+1字節數據而不是第n字節數據,接收方是不會發送序號為n+2的ACK的。舉個例子,假如接收端收到1-1024字節,它會發送一個確認號為1025的ACK,但是接下來收到的是2049-3072,它是不會發送確認號為3072的ACK,而依舊發送1025的ACK。
- 是當前的窗口大小m,如此發送方在接收到ACK包含的這兩個數據后就可以計算出還可以發送多少字節的數據給對方,假定當前發送方已發送到第x字節,則可以發送的字節數就是y=m-(x-n).
重點:
發送方根據收到ACK當中的期望收到的下一個字節的序號n以及窗口m,還有當前已經發送的字節序號x,算出還可以發送的字節數。
滑動窗口協議如圖所示:
在這個圖中,我們將字節從1至11進行標號。接收方通告的窗口稱為提出的窗口,它覆蓋了從第4字節到第9字節的區域,表明接收方已經確認了包括第3字節在內的數據,且通告窗口大小為6。我們知道窗口大小是與確認序號相對應的。發送方計算它的可用窗口,該窗口表明多少數據可以立即被發送。當接收方確認數據后,這個滑動窗口不時地向右移動。窗口兩個邊沿的相對運動增加或減少了窗口的大小。我們使用三個術語來描述窗口左右邊沿的運動:
- 窗口左邊沿向右邊沿靠近為窗口合攏。這種現象發生在數據被發送和確認時。
- 當窗口右邊沿向右移動時將允許發送更多的數據,我們稱之為窗口張開。這種現象發生在另一端的接收進程讀取已經確認的數據並釋放了T C P的接收緩存時。
- 當右邊緣向左移動時,稱之為窗口收縮。
每個TCP連接有發送窗口和接收窗口這兩個窗口。
TCP是雙工的協議,會話的雙方都可以同時接收、發送數據。
TCP會話的雙方都各自維護一個“發送窗口”和一個“接收窗口”。其中各自的“接收窗口”大小取決於應用、系統、硬件的限制(TCP傳輸速率不能大於應用的數據處理速率)。各自的“發送窗口”則要求取決於對端通告的“接收窗口”,要求相同。
TCP擁塞控制
在計算機網絡中的鏈路容量(即帶寬)、交換節點中的緩存和處理機等,都是網絡中的資源。在某段時間,若對網絡中某一資源的需求超過了該資源所能提供的可用部分,網絡的性能就會變壞。這種情況就叫做 擁塞。
擁塞控制 就是 防止過多的數據注入網絡中,這樣可以使網絡中的路由器或鏈路不致過載。
擁塞控制是一個全局性的過程,和流量控制不同,流量控制指點對點通信量的控制。
進行擁塞控制的四種算法:
- 慢開始(Slow-start)
- 擁塞避免(Congestion Avoidance)
- 快重傳(Fast Restrangsmit)
- 快恢復(Fast Recovery)。
慢開始和擁塞避免
發送方維持一個叫做擁塞窗口cwnd(congestion window)的狀態變量。擁塞窗口的大小取決於網絡的擁塞程度,並且動態地在變化。發送方讓自己的發送窗口等於擁塞窗口,另外考慮到接受方的接收能力,發送窗口可能小於擁塞窗口。
慢開始算法的思路就是,不要一開始就發送大量的數據,先探測一下網絡的擁塞程度,也就是說由小到大逐漸增加擁塞窗口的大小。在一開始發送方先設置cwnd=1,每經過一次傳輸輪次之后擁塞窗口就加倍(2的指數倍增加)。
為了防止窗口cwnd增長過大引起網絡擁塞,還需設置一個慢開始門限ssthresh狀態變量。ssthresh的用法如下:
- 當cwnd<ssthresh時,使用慢開始算法。
- 當cwnd>ssthresh時,改用擁塞避免算法。
- 當cwnd=ssthresh時,既可使用慢開始算法,也可使用擁塞算法。
擁塞避免算法讓擁塞窗口緩慢增長,即每經過一個往返時間RTT就把發送方的擁塞窗口cwnd加1,而不是加倍。這樣擁塞窗口按線性規律緩慢增長,比慢開始算法的擁塞窗口增長速率緩慢得多。
無論是在慢開始階段還是在擁塞避免階段,只要發送方判斷網絡出現擁塞(其根據就是沒有收到確認,雖然沒有收到確認可能是其他原因的分組丟失,但是因為無法判定,所以都當做擁塞來處理),就把慢開始門限設置為出現擁塞時的發送窗口大小的一半。然后把擁塞窗口設置為1,執行慢開始算法。
快重傳和快恢復
快重傳要求接收方在收到一個失序的報文段后就立即發出重復確認(為的是使發送方及早知道有報文段沒有到達對方)而不要等到自己發送數據時捎帶確認。快重傳算法規定,發送方只要一連收到三個重復確認就應當立即重傳對方尚未收到的報文段,而不必繼續等待設置的重傳計時器時間到期。由於發送方能 盡早重傳未被確認的報文段,因此采用快重傳算法后可以使整個網絡的吞吐量提高約20%。
快恢復算法,有以下兩個要點:
- 當發送方連續收到三個重復確認時,就執行“乘法減小”算法,把ssthresh門限減半。但是接下去並不執行慢開始算法。
- 考慮到如果網絡出現擁塞的話就不會收到好幾個重復的確認,所以發送方現在認為網絡可能沒有出現擁塞。所以此時不執行慢開始算法,而是將cwnd設置為ssthresh的大小,然后執行擁塞避免算法。
TCP和UDP的區別
- TCP面向連接,UDP面向非連接即發送數據前不需要建立鏈接。
- 面向連接的服務,通信雙方在進行通信之前,要先在雙方建立起一個完整的可以彼此溝通的通道,在通信過程中,整個連接的情況一直可以被實時地監控和管理。
- 非面向連接的服務,不需要預先建立一個聯絡兩個通信節點的連接,需要通信的時候,發送節點就可以往網絡上發送信息,讓信息自主地在網絡上去傳,一般在傳輸的過程中不再加以監控。
- TCP提供可靠的服務(數據傳輸),UDP無法保證。
- TCP面向字節流,UDP面向報文。
- TCP數據傳輸慢,UDP數據傳輸快。
注意:
TCP 並不能保證數據一定會被對方接收到,因為這是不可能的。
TCP的可靠性應該是相對於UDP不可靠傳輸來說的,因為UDP提供的是不可靠的數據報服務,不保證數據報能到達接收端,可能會有丟失;另外處於傳輸層之下的IP層也是不可靠的,僅提供盡力而為的端到端數據傳輸服務(best-effort delivery service),不作任何保證。
所以TCP的可靠性是指基於不可靠的IP層在傳輸層提供可靠的數據傳輸服務,如果有可能,就把數據遞送到接收方,否則就(通過放棄重傳並且中斷連接這一手段)通知用戶。因此准確說 TCP 也不是 100% 可靠的協議,它所能提供的是數據的可靠遞送或故障的可靠通知。
實現TCP的可靠傳輸有以下機制:
- 校驗和(校驗數據是否損壞)
- 定時器(分組丟失則重傳)
- 序號(用於檢測丟失的分組和冗余的分組)
- 確認(接收方告知發送方正確接收分組以及期望的下一個分組)
- 否定確認(接收方通知發送方未被正確接收的分組)
- 窗口和流水線(用於增加信道的吞吐量)。
至於數據是否在中途被修改或者被竊聽,這應該是屬於安全性問題。提高安全性最根本的辦法就是加密數據,比如遠程登錄用ssh而非telnet。
TCP、UDP對應的協議
TCP對應的協議
- FTP:定義了文件傳輸協議,使用21端口。
- Telnet:一種用於遠程登陸的端口,使用23端口,用戶可以以自己的身份遠程連接到計算機上,可提供基於DOS模式下的通信服務。
- SMTP:郵件傳送協議,用於發送郵件。服務器開放的是25號端口。
- POP3:它是和SMTP對應,POP3用於接收郵件。POP3協議所用的是110端口。
- HTTP:是從Web服務器傳輸超文本到本地瀏覽器的傳送協議。
UDP對應的協議
- DNS:用於域名解析服務,將域名地址轉換為IP地址。DNS用的是53號端口。
- SNMP:簡單網絡管理協議,使用161號端口,是用來管理網絡設備的。由於網絡設備很多,無連接的服務就體現出其優勢。
- TFTP(Trival File Transfer Protocal),簡單文件傳輸協議,該協議在熟知端口69上使用UDP服務。
SYN
攻擊
什么是 SYN
攻擊(SYN Flood)?
在三次握手過程中,服務器發送 SYN-ACK
之后,收到客戶端的 ACK
之前的 TCP 連接稱為半連接(half-open connect)。此時服務器處於 SYN_RCVD
狀態。當收到 ACK 后,服務器才能轉入 ESTABLISHED
狀態.
SYN
攻擊指的是,攻擊客戶端在短時間內偽造大量不存在的IP地址,向服務器不斷地發送SYN
包,服務器回復確認包,並等待客戶的確認。由於源地址是不存在的,服務器需要不斷的重發直至超時,這些偽造的SYN
包將長時間占用未連接隊列,正常的SYN
請求被丟棄,導致目標系統運行緩慢,嚴重者會引起網絡堵塞甚至系統癱瘓。
SYN
攻擊是一種典型的 DoS/DDoS
攻擊。
如何檢測 SYN
攻擊?
檢測 SYN
攻擊非常的方便,當你在服務器上看到大量的半連接狀態時,特別是源IP地址是隨機的,基本上可以斷定這是一次SYN
攻擊。在 Linux/Unix
上可以使用系統自帶的 netstats
命令來檢測 SYN
攻擊。
如何防御 SYN
攻擊?
SYN
攻擊不能完全被阻止,除非將TCP協議重新設計。我們所做的是盡可能的減輕SYN
攻擊的危害,常見的防御 SYN
攻擊的方法有如下幾種:
- 縮短超時(
SYN
Timeout)時間 - 增加最大半連接數
- 過濾網關防護
SYN
cookies技術