就是要搞一大堆原理性的東西,再回答標題的問題。說這個是因為我這次會把問題的答案就放到開頭嗎?不!我就不!但是大家可以直接根據(jù)目錄看自己感興趣的部分。之所以要先鋪墊一些原理,還是希望大家能先看些基礎的,再慢慢循序漸進,這樣有利于建立知識體系。多一點上下文,少一點
gap
。好了,進入正題。下面是這篇文章的目錄。什么是RST
我們都知道TCP正常情況下斷開連接是用四次揮手,那是正常時候的優(yōu)雅做法。但異常情況下,收發(fā)雙方都不一定正常,連揮手這件事本身都可能做不到,所以就需要一個機制去強行關閉連接。RST 就是用于這種情況,一般用來異常地關閉一個連接。它是一個TCP包頭中的標志位。正常情況下,不管是發(fā)出,還是收到置了這個標志位的數(shù)據(jù)包,相應的內(nèi)存、端口等連接資源都會被釋放。從效果上來看就是TCP連接被關閉了。而接收到 RST的一方,一般會看到一個connection reset
或 ?connection refused
的報錯。怎么知道收到RST了?
我們知道內(nèi)核跟應用層是分開的兩層,網(wǎng)絡通信功能在內(nèi)核,我們的客戶端或服務端屬于應用層。應用層只能通過send/recv
與內(nèi)核交互,才能感知到內(nèi)核是不是收到了RST
。當本端收到遠端發(fā)來的RST
后,內(nèi)核已經(jīng)認為此鏈接已經(jīng)關閉。此時如果本端應用層嘗試去執(zhí)行 讀數(shù)據(jù)操作,比如recv
,應用層就會收到 Connection reset by peer 的報錯,意思是遠端已經(jīng)關閉連接。send
,那么應用層就會收到 Broken pipe 的報錯,意思是發(fā)送通道已經(jīng)壞了。出現(xiàn)RST的場景有哪些
RST一般出現(xiàn)于異常情況,歸類為 對端的端口不可用 和 socket提前關閉。端口不可用
端口不可用分為兩種情況。要么是這個端口從來就沒有"可用"過,比如根本就沒監(jiān)聽(listen)過;要么就是曾經(jīng)"可用",但現(xiàn)在"不可用"了,比如服務突然崩了。端口未監(jiān)聽
listen
方法會創(chuàng)建一個sock
放入到全局的哈希表
中。此時客戶端發(fā)起一個connect
請求到服務端。服務端在收到數(shù)據(jù)包之后,第一時間會根據(jù)IP和端口從哈希表里去獲取sock
。listen
,就能從全局哈希表
里拿到sock
。但如果服務端沒有執(zhí)行過listen
,那哈希表
里也就不會有對應的sock
,結果當然是拿不到。此時,正常情況下服務端會發(fā)RST
給客戶端。端口未監(jiān)聽就一定會發(fā)RST嗎?
不一定。上面提到,發(fā)RST的前提是正常情況下,我們看下源碼。//?net/ipv4/tcp_ipv4.c??
//?代碼經(jīng)過刪減
int?tcp_v4_rcv(struct?sk_buff?*skb)
{
????//?根據(jù)ip、端口等信息?獲取sock。
????sk?=?__inet_lookup_skb(