TCP三向交握,四次揮手異常情況(坑)
(文中client,server均是相對而言)
(1)、client第一個syn包丢失,沒有收到server的ack,則client進行持續重傳syn包。總嘗試時間為75秒。參與文獻《TCP/IP詳解 卷1:協定》p178
(2)、server收到了client的syn,并發出了syn+ack包,syn+ack包丢失。
client方面,因為沒收server的。将執行情況(1);
server方面,逾時時間内沒有收到client的ack包(或者資料包),會持續發送syn+ack包;
(3)、當Client端收到Server的SYN+ACK應答後,其狀态變為ESTABLISHED,并發送ACK包給Server;
如果此時ACK在網絡中丢失,那麼Server端該TCP連接配接的狀态為SYN_RECV,并且依次等待3秒、6秒、12秒後重新發送SYN+ACK包,以便Client重新發送ACK包,以便Client重新發送ACK包。
Server重發SYN+ACK包的次數,可以通過設定/proc/sys/net/ipv4/tcp_synack_retries修改,預設值為5。
如果重發指定次數後,仍然未收到ACK應答,那麼一段時間後,Server自動關閉這個連接配接。
如果此時client向server發送資料包,server能正常接收資料。并認為連接配接已正常。
應用層編寫socket代碼時,三次握手發生在client的connect,是以為了避免長時間(75秒)無響應連接配接,應設定為非阻塞socket,同時用select檢測設定合适的逾時時間。
CLIENT SERVER

(1)、client發的FIN包丢了,對于client,因為沒收對應的ACK包,應當一直重傳(像普通包一樣),直至到達上限次數,直接關閉連接配接;對于server,它應該無任何感覺;
(2)、server回client的ACK包丢了,對于client,将執行(1),對于server将像丢普通的ack一樣,再次收到FIN後,再發一個ACK包;
(3)、如果client收到ACK後,server直接跑路。client将永遠停留在這個狀态(半打開狀态,就像client關閉了輸出一樣)。linux有tcp_fin_timeout這個參數,設定一個逾時時間 cat /proc/sys/net/ipv4/tcp_fin_timeout 檢視,預設60s,可否修改看linux具體版本; windows 系統資料庫有TcpTimedWaitDelay,win10預設值30s;
(4)、server發的FIN包丢了,對于server,像丢普通的包一樣,重傳。若此時client早已跑路且與其他人建立的連接配接,client應會不認識這個FIN包,直接回個RST包給server。
如若client沒跑路,且沒收到server的FIN包,如(3)描述;
(5)、client回複ACK後,按道理來說,可以跑路了,但防止回複的ACK包丢失(丢失後,server因為沒收FIN的ACK,是以會再發一個FIN),将等待2MSL(最大封包存活時間)(RFC793定義了MSL為2分鐘,Linux設定成了30s)為什麼要這有TIME_WAIT?為什麼不直接給轉成CLOSED狀态呢?主要有兩個原因:1)TIME_WAIT確定有足夠的時間讓對端收到了ACK,如果被動關閉的那方沒有收到Ack,就會觸發被動端重發Fin,一來一去正好2個MSL,2)有足夠的時間讓這個連接配接不會跟後面的連接配接混在一起(你要知道,有些自做主張的路由器會緩存IP資料包,如果連接配接被重用了,那麼這些延遲收到的包就有可能會跟新連接配接混在一起),這期間如若再收到server的FIN,則再回複ACK;
題外話:
可以看到時三次握手第二步時,server收到client的SYN包并回複SYN+ACK包後,server會把這條連接配接放入“半連接配接隊列”。這邊有個問題,假設這個client是惡意的,client隻發SYN包,收到SYN+ACK後不回複,那在server方面,會一直存有這條“半連接配接”,client數量達到一定程式,serve就炸了。這就是所謂的SYN FLOOD攻擊;那怎麼防止這種情況呢?有下面幾種方法:(來自RFC 4987)
過濾
增加積壓
減少SYN-RECEIVED定時
複用古老的半開通TCP
SYN緩存
SYN Cookie
混合方法
防火牆和代理
