圖解網(wǎng)絡(luò)|收到 RST,就一定會(huì)斷開(kāi) TCP 連接嗎?
[導(dǎo)讀]什么是RST我們都知道TCP正常情況下斷開(kāi)連接是用四次揮手,那是正常時(shí)候的優(yōu)雅做法。但異常情況下,收發(fā)雙方都不一定正常,連揮手這件事本身都可能做不到,所以就需要一個(gè)機(jī)制去強(qiáng)行關(guān)閉連接。RST就是用于這種情況,一般用來(lái)異常地關(guān)閉一個(gè)連接。它是一個(gè)TCP包頭中的標(biāo)志位。正常情況下,不...
什么是RST我們都知道TCP正常情況下斷開(kāi)連接是用四次揮手,那是正常時(shí)候的優(yōu)雅做法。但異常情況下,收發(fā)雙方都不一定正常,連揮手這件事本身都可能做不到,所以就需要一個(gè)機(jī)制去強(qiáng)行關(guān)閉連接。RST 就是用于這種情況,一般用來(lái)異常地關(guān)閉一個(gè)連接。它是一個(gè)TCP包頭中的標(biāo)志位。正常情況下,不管是發(fā)出,還是收到置了這個(gè)標(biāo)志位的數(shù)據(jù)包,相應(yīng)的內(nèi)存、端口等連接資源都會(huì)被釋放。從效果上來(lái)看就是TCP連接被關(guān)閉了。而接收到 RST的一方,一般會(huì)看到一個(gè) TCP報(bào)頭RST位 ResetByPeer 如果本端應(yīng)用層嘗試去執(zhí)行寫(xiě)數(shù)據(jù)操作,比如BrokenPipe 這兩個(gè)是開(kāi)發(fā)過(guò)程中很經(jīng)常遇到的報(bào)錯(cuò),感覺(jué)大家可以把這篇文章放進(jìn)收藏夾吃灰了,等遇到這個(gè)問(wèn)題了,再打開(kāi)來(lái)擦擦灰,說(shuō)不定對(duì)你會(huì)有幫助。TCP連接未監(jiān)聽(tīng)的端口 服務(wù)端全局hash表 如果服務(wù)端執(zhí)行過(guò)
connection reset 或 ?connection refused 的報(bào)錯(cuò)。怎么知道收到RST了?
我們知道內(nèi)核跟應(yīng)用層是分開(kāi)的兩層,網(wǎng)絡(luò)通信功能在內(nèi)核,我們的客戶(hù)端或服務(wù)端屬于應(yīng)用層。應(yīng)用層只能通過(guò)send/recv 與內(nèi)核交互,才能感知到內(nèi)核是不是收到了RST。當(dāng)本端收到遠(yuǎn)端發(fā)來(lái)的RST后,內(nèi)核已經(jīng)認(rèn)為此鏈接已經(jīng)關(guān)閉。此時(shí)如果本端應(yīng)用層嘗試去執(zhí)行 讀數(shù)據(jù)操作,比如recv,應(yīng)用層就會(huì)收到 Connection reset by peer 的報(bào)錯(cuò),意思是遠(yuǎn)端已經(jīng)關(guān)閉連接。send,那么應(yīng)用層就會(huì)收到 Broken pipe 的報(bào)錯(cuò),意思是發(fā)送通道已經(jīng)壞了。出現(xiàn)RST的場(chǎng)景有哪些
RST一般出現(xiàn)于異常情況,歸類(lèi)為 對(duì)端的端口不可用 和 socket提前關(guān)閉。端口不可用
端口不可用分為兩種情況。要么是這個(gè)端口從來(lái)就沒(méi)有"可用"過(guò),比如根本就沒(méi)監(jiān)聽(tīng)(listen)過(guò);要么就是曾經(jīng)"可用",但現(xiàn)在"不可用"了,比如服務(wù)突然崩了。端口未監(jiān)聽(tīng)
listen 方法會(huì)創(chuàng)建一個(gè)sock放入到全局的哈希表中。此時(shí)客戶(hù)端發(fā)起一個(gè)connect請(qǐng)求到服務(wù)端。服務(wù)端在收到數(shù)據(jù)包之后,第一時(shí)間會(huì)根據(jù)IP和端口從哈希表里去獲取sock。listen,就能從全局哈希表里拿到sock。但如果服務(wù)端沒(méi)有執(zhí)行過(guò)listen,那哈希表里也就不會(huì)有對(duì)應(yīng)的sock,結(jié)果當(dāng)然是拿不到。此時(shí),正常情況下服務(wù)端會(huì)發(fā)RST給客戶(hù)端。端口未監(jiān)聽(tīng)就一定會(huì)發(fā)RST嗎?
不一定。上面提到,發(fā)RST的前提是正常情況下,我們看下源碼。//?net/ipv4/tcp_ipv4.c??
//?代碼經(jīng)過(guò)刪減
int?tcp_v4_rcv(struct?sk_buff?*skb)
{
????//?根據(jù)ip、端口等信息?獲取sock。
????sk?=?__inet_lookup_skb( 




