簡單說說TCP(3) --- 斷開連線四次握手
四次握手流程
先來一張TCP斷開連線流程圖:(圖片來自於網路)
上圖中,A是主動關閉方,B是被動關閉方,四次握手可以描述為:
- 第一次握手:A告訴B,“我要關閉連線了”。
- 第二次握手:B回覆A,“我知道你要關閉了,但是請等一下,我還有資料沒有傳完,你等我訊息”。
- 第三次握手:B告訴A,“我的資料發完了,你可以關閉連線了”。
- 第四次握手:A回覆B,“好的,你先關吧,我2MSL時間後再關”。
出現大量CLOSE_WAIT的原因
被動關閉方收到主動關閉方發來的FIN,則會迴應ACK,並進入CLOSE_WAIT狀態。但如果被動關閉方不執行close(),就不能由CLOSE_WAIT遷移到LAST_ACK。在該狀態下,recv/read會返回0。
舉例來說,當主動關閉方呼叫closesocket的時候,被動關閉方的應用程式正在呼叫recv,這時候有可能應用程式沒有收到主動關閉方發來的FIN包,而是由TCP代回了一個ACK,所以就陷入CLOSE_WAIT出不來了。
TCP的KeepLive功能,可以讓作業系統替我們自動清理掉CLOSE_WAIT的連線。但是KeepLive在Windows作業系統下預設是7200秒,需要調整一下:
開啟登錄檔(執行 -> 輸入regedit -> 回車),在HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters裡修改:
KeepAliveTime REG_DWORD 300000
KeepAliveInterval REG_DWORD 1000
TcpMaxDataRetransmissions REG_DWORD 5
為什麼要有TIME_WAIT
讓4次握手關閉流程更加可靠。
若最後一個ACK丟失,被動關閉方會重新發一個FIN。在TIME_WAIT狀態內,主動關閉方收到重發的FIN後,會重發ACK。而倘若沒有2MSL的TIME_WAIT狀態,當主動關閉方收到重發的FIN後,會回覆一個RST,被動關閉方在收到RST後,會將其解釋成一個錯誤:connect reset by peer。
等待老的重複分節在網路中消逝,防止lost duplicate對後續新建的incarnation connection的傳輸造成破壞。
lost duplicate
:在實際的網路中非常常見,經常是由於路由器產生故障,路徑無法收斂,導致一個數據包在路由器A、B、C之間做類似死迴圈的跳轉。IP頭部有個TTL,限制了一個包在網路中的最大跳數。因此這個包有兩種命運,- TTL變為0,在網路中消失;
- TTL在變為0之前路由器路徑收斂,它憑藉剩餘的TTL跳數終於到達目的地。但非常可惜的是TCP通過超時重傳機制在早些時候傳送了一個跟它一模一樣的包,並且先於它到達了目的地,因此它註定被TCP協議棧拋棄;
incarnation connection
:跟上次的socket pair一模一樣的新連線。倘若沒有2MSL時間的TIME_WAIT狀態來等待lost duplicate失效,那麼就會出現如下情況,一個incarnation connection收到的seq=1000,這時來了一個lost duplicate為seq=1000,len=1000,則tcp認為這個lost duplicate合法,並存放入了receive buffer,導致傳輸出現錯誤。
TIME_WAIT狀態為什麼持續2MSL
MSL(Maximum Segment Lifetime)是指報文最大生存時間。RFC 793規範MSL為2min。然後,實際TCP實現中的常用值是30s、1min或2min。
之所以是2MSL而不是1MSL,是因為這裡面還包括了最後一個ACK在路上的時間。
2MSL在Windows上預設是4min。
TIME_WAIT帶來的問題
RFC要求socket pair在處於TIME_WAIT時,不能再起一個incarnation connection。但絕大部分TCP實現,強加了更為嚴格的限制,“在2MSL等待期間,socket中使用的本地埠在預設情況下不能再被使用”。
這個限制對於client來說是無所謂的,但是對於server,就嚴重了。一旦server端主動關閉了某個client的連線,導致server監聽的埠在2MSL時間內無法接受新的連線,這顯然是不行的。
方案一
保證由client主動發起關閉。方案二
server主動關閉的時候使用RST的方式,不進入 TIME_WAIT狀態。
具體做法是設定socket的SO_LINGER選項。方案三
給server的socket設定SO_REUSEADDR選項,這樣的話就算server埠處於TIME_WAIT狀態,在這個埠上依舊可以將服務啟動。當然,“非相同socket pair”這個限制依然存在,即在2MSL時間內仍然拒絕來自與之前斷掉的client相同ip和port的連線,錯誤資訊為address already in use。
程式碼如下:
int opt = 1;
setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
不過在BSD-derived實現和Windows Server 2003中,只要SYN的seq比上一次關閉時的最大seq還要大,那麼TIME_WAIT狀態一樣接受這個SYN。
方案四
Linux實現了一個TIME_WAIT狀態快速回收的機制,即無需等待2MSL這麼久的時間,而是等待一個Retrans時間即釋放,也就是等待一個重傳時間(一般超級短,以至於你都來不及能在netstat -ant中看到TIME_WAIT狀態)隨即釋放。
釋放了之後,一個連線的tuple元素資訊就都沒有了,而此時,新建立的TCP卻面臨著危險:- 可能被之前遲到的FIN包給終止
- 可能被之前連線劫持
於是需要有一定的手段避免這些危險。什麼手段呢?雖然曾經連線的tuple資訊沒有了,但是在IP層還可以儲存一個peer資訊,注意這個資訊不單單是用於TCP這個四層協議的,路由邏輯也會使用它,其欄位包括但不限於:
- 對端ip地址
- peer最後一次被TCP觸控到的時間戳
在快速釋放掉TIME_WAIT連線之後,peer依然保留著。丟失的僅僅是埠資訊。不過有了peer的IP地址資訊以及TCP最後一次觸控它的時間戳就足夠了,TCP規範給出一個優化,即一個新的連線除了同時觸犯了以下幾點,其它的均可以快速接入,即使它本應該處在TIME_WAIT狀態:
- 來自同一臺機器的TCP連線攜帶時間戳
- 之前同一臺peer機器(僅僅識別IP地址,因為連線被快速釋放了,沒了埠資訊)的某個TCP資料在MSL秒之內到過本機
- 新連線的時間戳小於peer機器上次TCP到來時的時間戳,且差值大於重放視窗戳
看樣子只有以上的3點的同時滿足才能拒絕掉一個新連線,要比TIME_WAIT機制設定的障礙導致的連線拒絕機率小很多,但是要看到,上述的快速釋放機制沒有埠資訊!這就把機率擴大了65535倍。然而,如果對於單獨的機器而言,這不算什麼,因為單臺機器的時間戳不可能倒流的,出現上述的3點均滿足時,一定是老的重複資料包又回來了。
但是,一旦涉及到NAT裝置,就悲催了,因為NAT裝置將資料包的源IP地址都改成了一個地址(或者少量的IP地址),但是卻基本上不修改TCP包的時間戳。TIME_WAIT快速回收在Linux上通過net.ipv4.tcp_tw_recycle啟用,由於其根據時間戳來判定,所以必須開啟TCP時間戳才有效。
建議:如果前端部署了三/四層NAT裝置,儘量關閉快速回收,以免發生NAT背後真實機器由於時間戳混亂導致的SYN拒絕問題。
Windows下調整TIME_WAIT時間
1、開啟登錄檔(執行 -> 輸入regedit -> 回車)
2、在HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters裡新增一項:
TcpTimedWaitDelay REG_DWORD 0x0000001e(30)
Linux下調整核心引數
編輯檔案:
vim /etc/sysctl.conf
加入以下內容:
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_fin_timeout = 30
最後執行:
/sbin/sysctl -p
使引數生效。
net.ipv4.tcp_syncookies = 1
開啟SYN cookies,當出現SYN等待佇列溢位時,啟用cookies來處理,可防範少量SYN攻擊。預設為0,表示關閉。net.ipv4.tcp_tw_reuse = 1
開啟重用。允許將TIME-WAIT sockets重新用於新的TCP連線,預設為0,表示關閉。net.ipv4.tcp_tw_recycle = 1
開啟TCP連線中TIME-WAIT sockets的快速回收,預設為0,表示關閉。net.ipv4.tcp_fin_timeout = 30
系統預設的 TIMEOUT 時間。
Linux下kill程序時對socket的關閉處理
Linux照顧到了一種特殊情況,即殺死程序的情況,在系統kill程序的時候,會直接呼叫連線的close函式單方面關閉一個方向的連線,然後並不會等待對端關閉另一個方向的連線程序即退出。現在的問題是,TCP規範和UNIX程序的檔案描述符規範直接衝突!程序關閉了,套接字就要關閉,但是TCP是全雙工的,你不能保證對端也在同一個時刻同意並且實施關閉動作,既然連線不能關閉,作為檔案描述符,程序就不會關閉得徹底!所以,Linux使用了一種“子狀態”的機制,即在程序退出的時候,單方面傳送FIN,然後不等後續的關閉序列即將連線拷貝到一個佔用資源更少的TW套接字,狀態直接轉入TIMW_WAIT,此時記錄一個子狀態FIN_WAIT_2,接下來的套接字就和原來的屬於程序描述符的連線沒有關係了。等到新的連線到來的時候,直接匹配到這個主狀態為TW,子狀態為FIN_WAIT_2的TW連線上,它負責處理FIN,FIN ACK等資料。
統計所有TCP連線的各種狀態的數量
netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'
相關推薦
簡單說說TCP(3) --- 斷開連線四次握手
四次握手流程 先來一張TCP斷開連線流程圖:(圖片來自於網路) 上圖中,A是主動關閉方,B是被動關閉方,四次握手可以描述為: 第一次握手:A告訴B,“我要關閉連線了”。 第二次握手:B回覆A,“我知道你要關閉了,但是請等一下,我還有資料沒有傳
TCP建立連線三次握手和釋放連線四次握手
TCP的報文結構如下下所示:序列號seq:佔4個位元組,用來標記資料段的順序,TCP把連線中傳送的所有資料位元組都編上一個序號,第一個位元組的編號由本地隨機產生;給位元組編上序號後,就給每一個報文段指派
Wireshark抓包示範:TCP三次握手建立連線和四次握手斷開連線
以下內容來自網路資源整合,僅供自己記錄,日後檢視方便。 首先介紹Wireshark抓包工具,它長這樣: 下面我們要設定過濾規則: 按如下設定,主要設定: 1、需要監控的網絡卡; 2、過濾規則(圖示是“HTTP TCP port(80)”,即只監控TCP連線):
TCP四次握手斷開連線
建立連線非常重要,它是資料正確傳輸的前提;斷開連線同樣重要,它讓計算機釋放不再使用的資源。如果連線不能正常斷開,不僅會造成資料傳輸錯誤,還會導致套接字不能關閉,持續佔用資源,如果併發量高,伺服器壓力堪憂。建立連線需要三次握手,斷開連線需要四次握手,可以形象的比喻為下面的對話
TCP/IP協議的三次握手和四次揮手(建立連線和斷開連線)
1、TCP/IP協議概述 TCP/IP協議(TransmissionControl Protocol/Internet Protocol)叫做傳輸控制/網際協議,又叫網路通訊協議,這個協議是Internet國際網際網路絡的基礎。TCP/IP是網路中使用的基本的通訊協議。雖然
TCP建立連接的三次握手和TCP連接斷開的四次揮手
bubuko 信息 發送數據 數據 可靠的 註意 過程 接收 告訴 1. TCP建立連接的3次握手 2. TCP斷開連接的四次揮手 【註意】中斷連接端可以是Client端,也可以是Server端。 圖3
TCP鏈接的三次握手與四次斷開
浪費 seq 建立連接時 tab 背景條 客戶端 設計 received 上帝 一直總覺得三次握手和四次斷開,之前老師講的有問題,經過自己再次琢磨,發現是的,老師講的沒毛病,這次也把自己的理解總結一下,讓對這個知識模糊的小夥伴再換種思路去理解 首先看一下TCP三次握手發生了
TCP連線 三次握手 四次揮手
前言: TCP協議是面向連線、安全可靠、基於位元組流的傳輸層協議,在進行http協議訪問時就用到了tcp連線。在建立TCP連線時需要經歷三次握手,斷開連線時需要經歷四次揮手。在此進行記錄。 內容: TCP三次握手 第一次握手:由客戶端發起,客戶端生成一個SYN,以及一個
TCP/IP詳解--TCP三次握手建立連線與四次握手終止連線
1.TCP連線的建立 (1)首先是伺服器初始化的過程,從CLOSED(關閉)狀態開始通過順序呼叫SOCKET、BIND、LISTEN和ACCEPT原語建立Socket套接字,進入LISTEN(監聽)狀態,等待客戶端的TCP傳輸連線請求。 (2)客戶端最開始也是從CLOSED狀態開始呼叫SOCKET
TCP/IP TIME_WAIT狀態原理(四次握手關閉連線原理)
TIME_WAIT狀態原理 ---------------------------- 通訊雙方建立TCP連線後,主動關閉連線的一方就會進入TIME_WAIT狀態。 客戶端主動關閉連線時,會發送最後一個ack後,然後會進入TIME_WAIT狀態,再停留2個MSL時間(後有MS
簡單說明TCP的狀態和三次握手、四次握手
在TCP層,有個FLAGS欄位,這個欄位有以下幾個標識:SYN, FIN, ACK, PSH, RST, URG. 其中,對於我們日常的分析有用的就是前面的五個欄位。 它們的含義是: SYN表示建立連線, FIN表示關閉連線, ACK表示響應, PSH表示有 DATA資料傳輸, RST表示連線重置。 其
TCP連線三次握手和四次揮手
1、三次握手 (1)三次握手的詳述 首先Client端傳送連線請求報文,Server段接受連線後回覆ACK報文,併為這次連線分配資源。Client端接收到ACK報文後也向Server段發生ACK報文,並分配資源,這樣TCP連線就建立了。 最初兩端的TCP程
為什麼tcp建立連線是三次握手而不是兩次握手或者四次握手?(筆試面試常考)
先說說tcp三次握手, 不細說了, 也就是syn, ack/syn, ack. 為什麼不能是兩次呢? 先假設是兩次吧。我們知道, tcp的連線過程中有一個超時重傳演算法(karn演算法是比較典型的), 如果client發
TCP/IP的三次握手連線和四次握手關閉
(1)第一次握手:建立連線時,客戶端A傳送SYN包(SYN=j)到伺服器B,並進入SYN_SEND狀態,等待伺服器B確認。 (2)第二次握手:伺服器B收到SYN包,必須確認客戶A的SYN(ACK=j+1),同時自己也傳送一個SYN包(SYN=k),即SYN+ACK包,此時伺服器B進入SYN_RECV狀態。
為什麼TCP建立連線協議是三次握手,而關閉連線卻是四次握手呢?
看到了一道面試題:“為什麼TCP建立連線協議是三次握手,而關閉連線卻是四次握手呢?為什麼不能用兩次握手進行連線?”,想想最近也到金三銀四了,所以就查閱了相關資料,整理出來了這篇文章,希望對你們有所幫助。 TCP 連線 我們先來補一下基礎什麼是 TCP 協議?傳輸控制協議( Transmission Contr
tcp協議報文和三次握手與四次揮手
tcp報文 三次握手與四次揮手 tcp11種狀態tcp協議:tcp是面向連接、可靠的進程到進程之間的協議。tcp提供全雙工服務:即:數據可在同一時間雙向傳輸。tcp報文段首部格式:各字段含義:源端口號:16位字段,為發送端進程對應的端口號目標端口:16位字段,為接收端進程對應的端口號,接收方接收到數據
【轉】TCP建立連接三次握手和釋放連接四次握手
eight 請求 置1 計時器 響應 發送數據 出現 期望 本地 在談及TCP建立連接和釋放連接過程,先來簡單認識一下TCP報文段首部格式的的幾個名詞(這裏只是簡單說明,具體請查看相關教程) 序列號seq:占4個字節,用來標記數據段的順序,TCP把連接中發送的所有數
為什麽TCP連接需要三次握手分開需要四次握手?
發送數據 回復 兩件 請求 com 可靠性 網絡 浪費 準備工作 原文地址:http://lixiangfeng.com/blog/article/content/7908246 TCP的三次握手和四次斷開TCP是一個面向連接的服務,面向連接的服務是電話系統服務模式的抽象,
TCP關閉的四次握手
logs nbsp -1 握手 cnblogs eight images 返回 client 主動方(Client);http為服務器,close--->調用tcp的FIN關鍵字 被動方寫入EOF,然後返回ACK確認,再close-->tcp發送FIN關閉 主
TCP協議中的三次握手和四次揮手(圖解)(轉)
繼續 丟失 get 所有 如果 idt 請求報文 網絡 center 轉自:http://blog.csdn.net/whuslei/article/details/6667471 建立TCP需要三次握手才能建立,而斷開連接則需要四次握手。整個過程如下圖所示: 先來看看如