傳輸控制協(xié)議 TCP(Transmission Control Protocol)
特點
是面向連接的,提供可靠交付,有流量控制,擁塞控制,提供全雙工通信,面向字節(jié)流(把應用層傳下來的報文看成字節(jié)流,把字節(jié)流組織成大小不等的數(shù)據(jù)塊),每一條 TCP 連接只能是點對點的(一對一)。-
首部
image.png
選項: 0~40字節(jié) TCP校驗和的實現(xiàn)
TCP校驗和由發(fā)送端計算,接收端驗證。目的是為了發(fā)現(xiàn)TCP首部和數(shù)據(jù)在發(fā)送端到接收端之間發(fā)生的任何改動。TCP校驗和覆蓋TCP首部和TCP數(shù)據(jù),校驗和是必須的,并要加上12字節(jié)的偽首部(數(shù)據(jù)從IP數(shù)據(jù)報頭獲取,目的是讓TCP檢查數(shù)據(jù)是否已正確到達目的地)。
首先,把偽首部、TCP報頭、TCP數(shù)據(jù)分為16位的字,如果總長度為奇數(shù)個字節(jié),則在最后增添一個位都為0的字節(jié)。把TCP報頭中的校驗和字段置為0
然后,用反碼相加法累加所有的16位字(進位也要累加)
最后,對計算結果取反,作為TCP的校驗和連接管理
三次握手和四次揮手的原理
- 三次握手建立
在socket編程中,客戶端執(zhí)行connect()操作即可觸發(fā)三次握手
image.png
- 第一步:客戶機的TCP首先向服務器的 TCP 發(fā)送一個連接請求報文段。這個特殊的報文段中不含應用層數(shù)據(jù),其首部中的 SYN 標志位被置為1.另外,客戶機會隨機選擇一個起始序號 seq=x (連接請求報文不攜帶數(shù)據(jù),但要消耗掉一個序號)。然后客戶端進入 SYN-SENT 狀態(tài),等待服務器的確認
- 第二步:服務器的 TCP 收到連接請求報文后,如同意建立連接,就向客戶機發(fā)回確認,并為該 TCP 連接分配 TCP 緩存和變量。在確認報文段中,SYN 和 ACK 位都被置為 1 ,確認號字段ack的值為 x+1,并且服務器隨機產(chǎn)生起始序號 seq=y (確認報文不攜帶數(shù)據(jù),但也要消耗掉一個序號)。確認報文段同樣不包含應用層數(shù)據(jù)。
- 第三步:當客戶機收到確認報文段后,還要向服務器給出確認,并且也要給該連接分配緩存和變量。這個報文段的 ACK 標志為被置 1,序號字段seq為 x+1,確認號字段 ack=y+1。該報文段可以攜帶數(shù)據(jù),如果不攜帶數(shù)據(jù)則不消耗序號。
為什么 "三次握手" 而不是 "兩次握手" 建立連接:
防止兩次握手情況下已失效的連接請求報文突然又傳送到服務器而產(chǎn)生錯誤。
三次握手的目的:確認對方的接收與發(fā)送能力是否正常。
考慮客戶A向服務器B發(fā)出TCP連接請求:
第一個連接請求報文在網(wǎng)絡的某個結點長時間滯留,A超時后認為報文丟失,于是再重傳一次連接請求,B收到后建立連接。
數(shù)據(jù)傳輸完畢后雙方斷開連接。而此時,前一個滯留在網(wǎng)絡中的連接請求到達服務器B,而B認為A又發(fā)來連接請求,
此時若使用“三次握手”,則B向A返回確認報文段,由于是一個失效的請求,因此A 不予理睬,建立連接失敗。
若采用“兩次握手”,則這種情況下B認為傳輸連接已經(jīng)建立,并一直等待A傳輸數(shù)據(jù),而A此時并沒有連接請求,因此不予理睬,這樣就白白浪費B的資源。
半連接: 服務器第一次收到客戶端的SYN之后,就會處于SYN_RCVD狀態(tài),此時雙方還沒有完全建立連接,服務器把此種狀態(tài)下請求連接放在一個隊列中,這種隊列稱之為半連接隊列
全連接: 已完成三次握手,建立起連接的就會放在全連接隊列中。如果隊列滿就可能出現(xiàn)丟包現(xiàn)象。
三次握手是否可以攜帶數(shù)據(jù): 第一次、第二次握手不可以攜帶數(shù)據(jù)。因為第一次握手若攜帶數(shù)據(jù),會讓服務器更加容易受到SYN攻擊。第三次的話,客戶端已經(jīng)處于ESTABLISHED狀態(tài),對于客戶端來說,已經(jīng)建立起連接,并知道服務器的接收,發(fā)送能力正常,所以能攜帶數(shù)據(jù)。
SYN攻擊:
服務器的資源分配是在第二次握手時分配,客戶端資源是在完成三次握手時分配。,所以服務器容易受到SYN洪泛攻擊。SYN攻擊就是Client短時間內(nèi)偽造大量不存在的IP地址,并向Server不斷發(fā)送SYN包,Server則回復確認包,并等待Client確認,由于源地址不存在,因此Server需要不斷重發(fā)直至超時,這些偽造的SYN包將長時間占用未連接隊列,導致正常的SYN請求因為隊列滿而被丟棄,從而引起網(wǎng)絡擁塞甚至系統(tǒng)癱瘓。SYN攻擊是一種典型的Dos/DDos攻擊。
解決策略:
SYN cookies技術當服務器接受到 SYN 報文段時,不直接為該 TCP 分配資源,而只是打開一個半開的套接字。接著會使用 SYN 報文段的源 Id,目的 Id,端口號以及只有服務器自己知道的一個秘密函數(shù)生成一個 cookie,并把 cookie 作為序列號響應給客戶端。
如果客戶端是正常建立連接,將會返回一個確認字段為 cookie + 1 的報文段。接下來服務器會根據(jù)確認報文的源 Id,目的 Id,端口號以及秘密函數(shù)計算出一個結果,如果結果的值 + 1 等于確認字段的值,則證明是剛剛請求連接的客戶端,這時候才為該 TCP 分配資源,這樣一來就不會為惡意攻擊的 SYN 報文段分配資源空間,避免了攻擊。
過濾網(wǎng)關防護
增加最大半連接數(shù)
縮短超時(SYN Timeout)時間
- 四次揮手
在socket編程中,任何一方執(zhí)行close()操作即可產(chǎn)生揮手操作
四次揮手釋放TCP連接
- 第一步:客戶端打算關閉連接,就向其 TCP 發(fā)送一個連接釋放報文段,并停止再發(fā)送數(shù)據(jù),主動關閉 TCP 連接,該報文的 FIN 標志位被置為 1,seq=u,它等于前面已傳送過的數(shù)據(jù)的最夠一個字節(jié)的序號加 1 (FIN 報文段即使不攜帶數(shù)據(jù),也要消耗掉一個序號)。TCP 是全雙工的,即可以想象成是一條 TCP 連接上的兩條數(shù)據(jù)通路。當發(fā)送 FIN 報文時,發(fā)送 FIN 的一端就不能再發(fā)送數(shù)據(jù),也就是關閉了其中一條數(shù)據(jù)通路,但對方還可以發(fā)送數(shù)據(jù)
- 第二步:服務器收到連接釋放報文段后即發(fā)出確認,確認號是 ack=u+1,而這個報文段自己的序號是 v,等于它前面已傳送過的數(shù)據(jù)的最后一個字節(jié)的序號加 1。此時,從客戶機到服務器這個方向的連接就釋放了,TCP 連接處于半關閉狀態(tài)。但服務器若發(fā)送數(shù)據(jù),客戶機仍要接收,即從服務器到客戶機這個方向的連接并未關閉
- 第三步:若服務器已經(jīng)沒有要向客戶機發(fā)送的數(shù)據(jù),就通知 TCP 釋放連接,此時其發(fā)出 FIN=1 的連接釋放報文段
- 第四步:客戶機收到連接釋放報文段后,必須發(fā)出確認。在確認報文段中,ACK 字段被置為 1,確認號 ack=w+1,序號 seq=u+1。此時 TCP 連接還沒有釋放掉,必須等待時間計時器設置的時間 2MSL 后,A 才進入到連接關閉狀態(tài)。
常用的三個狀態(tài)是:ESTABLISHED 表示正在通信,TIME_WAIT 表示主動關閉,CLOSE_WAIT 表示被動關閉。
TIME_WAIT 狀態(tài)存在的必要性
- 客戶端最后向服務器發(fā)送的確認 ACK 是有可能丟失的(可靠的關閉TCP連接。)
為了保證 客戶端發(fā)送的最后一個確認報文段能夠到達服務器端。如果 客戶端 不等待 2MSL,在此期間若 客戶端返回的最后確認報文段丟失,則 服務器不能進入正常關閉狀態(tài),而 客戶端此時已經(jīng)關閉,也不可能再重傳。 - 避免新舊連接混雜(.防止上一次連接中的包,迷路后重新出現(xiàn),影響新連接(經(jīng)過2MSL,上一次連接中所有的重復包都會消失))
客戶端在發(fā)送完最后一個確認報文段后,再經(jīng)過 2MSL 可保證本連接持續(xù)的時間內(nèi)所產(chǎn)生的所有報文段從網(wǎng)絡中消失。
假設沒有time-wait 限制,因某些原因我們先關閉這條TCP連接,然后很快又以相同的<源ip,源port,目的ip,目的port> 建立一個新的TCP連接,然后發(fā)送數(shù)據(jù),設想此時前一個連接在網(wǎng)絡中滯留的數(shù)據(jù)報現(xiàn)在到達接收方,會被當做正常數(shù)據(jù)接收并上傳到應用層,而這些舊數(shù)據(jù)不應該被接收。從而引起數(shù)據(jù)錯亂而導致各種無法預知詭異錯誤
服務器保持大量的time-wait 狀態(tài)如何避免 - 讓服務器能夠快速回收和重用那些TIME_WAIT的資源。
#表示開啟重用。允許將TIME-WAIT sockets重新用于新的TCP連接,默認為0,表示關閉
net.ipv4.tcp_tw_reuse = 1
#表示開啟TCP連接中TIME-WAIT sockets的快速回收,默認為0,表示關閉
net.ipv4.tcp_tw_recycle = 1
- SO_REUSEADDR 套接字(so_resueaddr)
首先服務器可以設置 SO_REUSEADDR 套接字選項來通知內(nèi)核,如果端口忙,但TCP連接位于TIME_WAIT狀態(tài)時可以重用端口。在一個非常有用的場景就是,如果你的服務器程序停止后想立即重啟,而新的套接字依舊希望使用同一端口,此時SO_REUSEADDR選項就可以避免TIME_WAIT狀態(tài)。
服務器出現(xiàn)了大量 CLOSE_WAIT 狀態(tài)如何解決
說明在對方關閉連接之后服務器程序自己沒有進一步發(fā)出ack信號。換句話說,就是在對方連接關閉之后,程序里沒有檢測到,或者程序壓根就忘記了這個時候需要關閉連接,于是這個資源就一直被程序占著。
解決方法:檢查代碼,特別是釋放資源的代碼,或者是處理請求的線程配置。
流量控制和擁塞控制
流量控制和擁塞控制2
TCP擁塞控制
發(fā)送方根據(jù)自己的網(wǎng)絡擁塞程度設置cwnd(擁塞窗口)的值來限制發(fā)送速率
- 方法
ssthtresh是慢開始門限值
- 慢開始算法
cwnd<ssthresh,每收到一個對新報文段的確認后,將cwnd加1
- 擁塞避免算法
cwnd>ssthresh時,每經(jīng)過一個往返時延RTT,cwnd就增加一個 - 快重傳
當收到連續(xù)的三個重復ACK,直接重傳對方期待的報文 -
快恢復
當收到三個連續(xù)的冗余ACK(即重復確認),執(zhí)行“乘法減少”算法,令ssthresh=cwnd=cwnd/2
image.png
TCP流量控制
TCP提供一種基于滑動窗口協(xié)議的流量控制機制,接收方根據(jù)自己接收緩存的大小,動態(tài)調(diào)整發(fā)送方的發(fā)送窗口大小。
滑動窗口的基本原理:
由接收方控制發(fā)送方發(fā)送數(shù)據(jù)的速率。
停止-等待協(xié)議: 發(fā)送窗口大小 =1 ,接收窗口大小 = 1.保證有序接收
后退N幀協(xié)議: 發(fā)送窗口大小>1,接收窗口大小 =1.保證有序接收
選擇重傳協(xié)議: 發(fā)送窗口大小>1,接收窗口大小>1.
#######滑動窗口、窗口、擁塞窗口的區(qū)分?
滑動窗口:批量發(fā)送報文的大小,提高發(fā)送報文的效率
擁塞窗口:當前網(wǎng)絡可能造成擁堵的一個上限值/閾值
窗口:對象能接受的當前的最大的報文值
滑動窗口 = min[窗口,擁塞窗口]



