root@python:~# tcpdump -n -S tcp port 5009 # -S 參數的目的是得到ack的絕對值,不加該參數,第三次握手的ack爲相對值1 tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes 17:35:43.707223 IP 122.235.85.89.49302 > 172.16.10.164.5009: Flags [S], seq 267775201, win 8192, options [mss 1452,nop,wscale 2,nop,nop,sackOK], length 0 # **客戶端發起請求,第一次握手** 17:35:43.707299 IP 172.16.10.164.5009 > 122.235.85.89.49302: Flags [S.], seq 3046340720, ack 267775202, win 29200, options [mss 1460,nop,nop,sackOK,nop,wscale 7], length 0 17:35:43.729057 IP 122.235.85.89.49302 > 172.16.10.164.5009: Flags [.], ack 3046340721, win 16698, length 0 # **三次握手結束** 17:35:43.778243 IP 122.235.85.89.49302 > 172.16.10.164.5009: Flags [P.], seq 267775202:267775428, ack 3046340721, win 16698, length 226 # **開始傳送數據** 17:35:43.778299 IP 172.16.10.164.5009 > 122.235.85.89.49302: Flags [.], ack 267775428, win 237, length 0 17:35:43.780225 IP 172.16.10.164.5009 > 122.235.85.89.49302: Flags [.], seq 3046340721:3046343625, ack 267775428, win 237, length 2904 17:35:43.780254 IP 172.16.10.164.5009 > 122.235.85.89.49302: Flags [P.], seq 3046343625:3046343827, ack 267775428, win 237, length 202 17:35:43.802585 IP 122.235.85.89.49302 > 172.16.10.164.5009: Flags [.], ack 3046343827, win 16698, length 0 17:35:43.803603 IP 122.235.85.89.49302 > 172.16.10.164.5009: Flags [P.], seq 267775428:267775619, ack 3046343827, win 16698, length 191 17:35:43.803988 IP 172.16.10.164.5009 > 122.235.85.89.49302: Flags [P.], seq 3046343827:3046343878, ack 267775619, win 245, length 51 17:35:43.825824 IP 122.235.85.89.49302 > 172.16.10.164.5009: Flags [P.], seq 267775619:267775895, ack 3046343878, win 16685, length 276 17:35:43.865696 IP 172.16.10.164.5009 > 122.235.85.89.49302: Flags [.], ack 267775895, win 254, length 0 17:35:44.314454 IP 172.16.10.164.5009 > 122.235.85.89.49302: Flags [.], seq 3046343878:3046346782, ack 267775895, win 254, length 2904 17:35:44.314472 IP 172.16.10.164.5009 > 122.235.85.89.49302: Flags [.], seq 3046346782:3046349686, ack 267775895, win 254, length 2904 17:35:44.314477 IP 172.16.10.164.5009 > 122.235.85.89.49302: Flags [.], seq 3046349686:3046352590, ack 267775895, win 254, length 2904 17:35:44.314482 IP 172.16.10.164.5009 > 122.235.85.89.49302: Flags [P.], seq 3046352590:3046352839, ack 267775895, win 254, length 249 17:35:44.336458 IP 122.235.85.89.49302 > 172.16.10.164.5009: Flags [.], ack 3046352839, win 16698, length 0 17:35:44.402718 IP 122.235.85.89.49302 > 172.16.10.164.5009: Flags [P.], seq 267775895:267775926, ack 3046352839, win 16698, length 31 17:35:44.402758 IP 172.16.10.164.5009 > 122.235.85.89.49302: Flags [.], ack 267775926, win 254, length 0 17:35:44.402869 IP 172.16.10.164.5009 > 122.235.85.89.49302: Flags [F.], seq 3046352839, ack 267775926, win 254, length 0 # **四次揮手開始** 17:35:44.404033 IP 122.235.85.89.49302 > 172.16.10.164.5009: Flags [F.], seq 267775926, ack 3046352839, win 16698, length 0 17:35:44.404047 IP 172.16.10.164.5009 > 122.235.85.89.49302: Flags [.], ack 267775927, win 254, length 0 17:35:44.424589 IP 122.235.85.89.49302 > 172.16.10.164.5009: Flags [.], ack 3046352840, win 16698, length 0 # **四次揮手結束**
S=SYN 發起鏈接標誌。 P=PUSH 傳送數據標誌。 F=FIN 關閉鏈接標誌。 ACK 表示確認包。 RST=RESET 異常關閉鏈接。 . 表示沒有任何標誌。
客戶端A,服務器B,初始序號seq,確認號ack 初始狀態:B處於監聽狀態,A處於打開狀態 A -> B : seq = x (A向B發送鏈接請求報文段,A進入同步發送狀態SYN-SENT) B -> A : ack = x + 1,seq = y (B收到報文段,向A發送確認,B進入同步收到狀態SYN-RCVD) A -> B : ack = y+1 (A收到B的確認後,再次確認,A進入鏈接狀態ESTABLISHED) 鏈接後的狀態:B收到A的確認後,進入鏈接狀態ESTABLISHED
A -> B : seq = u (A發出鏈接釋放報文段,進入終止等待1狀態FIN-WAIT-1) B -> A : ack = u + 1,seq = v (B收到報文段,發出確認,TCP處於半關閉,B還可向A發數據,B進入關閉等待狀態WAIT) B -> A : ack = u + 1,seq = w (B重複發送確認號,進入最後確認狀態LAST-ACK) A -> B : ack = w + 1,seq = u + 1 (A發出確認,進入時間等待狀態TIME-WAIT) 通過時間等待計時器設置的時間2MSL後,A才進入CLOSED狀態
三次握手的最主要目的是保證鏈接是雙工的,可靠更多的是經過重傳機制來保證的。
這是由於服務端在LISTEN狀態下,收到創建鏈接請求的SYN報文後,把ACK和SYN放在一個報文裏發送給客戶端。而關閉鏈接時,當收到對方的FIN報文時,
僅僅表示對方再也不發送數據了可是還能接收數據,咱們也未必所有數據都發送給對方了,因此咱們不能夠當即close,也能夠發送一些數據給對方後,
再發送FIN報文給對方來表示贊成如今關閉鏈接,所以,咱們的ACK和FIN通常都會分開發送。html
TCP 鏈接的每一端都必須設有兩個窗口——一個發送窗口和一個接收窗口。TCP 的可靠傳輸機制用字節的序號進行控制。TCP 全部的確認都是基於序號而不是基於報文段。
發送過的數據未收到確認以前必須保留,以便超時重傳時使用。發送窗口沒收到確認不動,和收到新的確認後前移。python
發送緩存用來暫時存放: 發送應用程序傳送給發送方 TCP 準備發送的數據;TCP 已發送出但還沒有收到確認的數據。
接收緩存用來暫時存放:按序到達的、但還沒有被接收應用程序讀取的數據; 不按序到達的數據。緩存
RST表示鏈接重置,用於關閉那些已經沒有必要繼續存在的鏈接。通常狀況下表示異常關閉鏈接,區別與四次分手正常關閉鏈接。服務器
大多都寫開啓net.ipv4.tcp_tw_recycle這個開關,能夠快速回收處於TIME_WAIT狀態的socket(針對Server端而言)。
而實際上,這個開關,須要net.ipv4.tcp_timestamps(默認開啓)這個開關開啓纔有效果。
更被提到卻很重要的一個信息是:當tcp_tw_recycle開啓時(tcp_timestamps同時開啓,快速回收socket的效果達到),對於位於NAT設備後面的Client來講,
是一場災難——會導到NAT設備後面的Client鏈接Server不穩定(有的Client能鏈接server,有的Client不能鏈接server)。
也就是說,tcp_tw_recycle這個功能,是爲「內部網絡」(網絡環境本身可控——不存在NAT的狀況)設計的,對於公網不宜使用。網絡