什么是半開連接?
眾所周知缚甩,TCP三次握手完成才能認(rèn)為是雙方建立起連接,溫故而知新窑邦,先回顧一下三次握手的過程
如果連接建立后不再進(jìn)行任務(wù)數(shù)據(jù)交互的話擅威,服務(wù)端直接掛了,比如斷網(wǎng)宕機(jī)了冈钦,此時(shí)客戶端是無(wú)法與服務(wù)端通信的郊丛,但是客戶端并不知道這件事,此時(shí)這條TCP連接就可以認(rèn)為是半開連接瞧筛,還是來(lái)一條書本的定義吧:
如果在未告知另一端的情況下通信的一端關(guān)閉或是終止連接厉熟,那么就認(rèn)為該條TCP連接處于半開狀態(tài)
wireshark抓包
服務(wù)端開啟動(dòng)一個(gè)server如下所示:
? python3 -m http.server 12345
客戶端向服務(wù)端發(fā)起請(qǐng)求
? telnet 192.168.199.183 12345
客戶端啟用wireshark監(jiān)聽12345
端口
1665、1666较幌、1667三個(gè)數(shù)據(jù)包完成握手揍瑟,已知1666號(hào)包服務(wù)端的[SYN, ACK]包中,服務(wù)端告知客戶端自己的窗口大小為65535
而1668號(hào)包[TCP Window Update]:
服務(wù)端告知客戶端窗口大小為131712(即2058*64)
服務(wù)端窗口變大了乍炉,這屬于滑動(dòng)窗口相關(guān)內(nèi)容绢片,此處就不作展開了
服務(wù)端重啟
服務(wù)端斷網(wǎng)殺掉server滤馍,重開一個(gè)server,如之前的一樣
? python3 -m http.server 12345
此時(shí)客戶端輸入字符a
然后回車底循,所圖3046號(hào)包所示
此時(shí)服務(wù)不再記得之前的這條連接巢株,所以回了一個(gè)[RST]報(bào)文如下所示:
原因分析
系統(tǒng)用一個(gè)4四元組來(lái)唯一標(biāo)識(shí)一個(gè)TCP連接,即[src_ip:src_port, dst_ip:dst_port]熙涤,從我所構(gòu)造的這個(gè)半開連接抓包楊景來(lái)看阁苞,這四元組是沒有發(fā)生變化的,那么問題來(lái)了:服務(wù)端如何判斷是否與客戶端建立起連接?
回到我們所構(gòu)造的場(chǎng)景
- 服務(wù)端啟動(dòng)server
- 客戶端發(fā)起連接
- 服務(wù)器斷網(wǎng)殺掉并啟動(dòng)一個(gè)server祠挫,監(jiān)聽相同的端口
- 客戶端發(fā)送數(shù)據(jù)
- 服務(wù)端返回RST
我們知道三次握手后server端會(huì)維護(hù)一個(gè)accept隊(duì)列(當(dāng)然還有SYN隊(duì)列)那槽,我們的構(gòu)造的情況是server殺掉重開,雖然端口一樣茸歧,但這是一個(gè)新的進(jìn)程倦炒,此時(shí)accept隊(duì)列自然為空,所以當(dāng)客戶端向這個(gè)相同ip及端口的server發(fā)送數(shù)據(jù)據(jù)软瞎,服務(wù)端自然不能識(shí)別這個(gè)連接逢唤。
不過,這個(gè)分析只是基于現(xiàn)象進(jìn)行的推理涤浇,具體處理過程恐怕還得從socket連接及I/O過程及程序代碼說(shuō)起鳖藕,先開個(gè)坑,欲知詳情如何只锭,且聽下回分解
參考: