架構師:比起 404,我們更怕 200!
少年,你在懷著非法的心態看一篇簡短的硬核科普!
先拋問題:如何殺掉一個正在等待 TCP 連接的 Thread?
由于眾所周知的原因,在國內使用 maven,會等待很長的時間來下載相應的 jar 包。
如果我們正在使用 IDEA,就經常容易卡住。當我們點擊進度條的時候,無論是等待,還是取消,都需要等待比較長的時間來完成當前的網絡請求。
除非我們立馬把 IDEA 關掉,然后再重新打開它。
why?
因為你沒法用代碼殺掉一條處于連接狀態的連接。操作系統沒有有暴露這樣的 API!
但你可以殺掉進程。當進程停止的時候,與之關聯的所有連接都會被釋放。但是你無法殺掉線程,因為線程正在 BLOCK 在某個連接之上,你需要先關掉這個連接才能讓線程自動釋放。
一般的連接工具包,都會提供 soTimeout 這個參數,用來配置超時。比如 MySQL 客戶端:
通過設置超時時間可以防止出現網絡錯誤時一直等待的情況并縮短故障時間,防止死連接的產生。但如果連接沒有設置超時呢?
它就會永遠 Block 在那里!
在 Linux 上,有 tcpkill、killcx 等工具,可以殺掉一條處于 established 狀態的連接。
以tcpkill為例,我們需要安裝相應的工具包。
然后,使用netstat 或者 ss, 或者 lsof 等命令,找到要殺掉的連接。然后殺掉它。
執行了這樣的操作之后,Thread 就能夠自動正常關閉了。
那它是怎么實現的呢?
這又和老生常談的 TCP 四次揮手有關了。
想要關掉一條連接,需要經過 FIN 包和 ACK 包做四次揮手。這個過程很麻煩,但不要忘了,我們還有 RST 包,它可以直接引起連接的關閉。
可惜的是,如果你想要發送 RST 包,那必須首先要知道交互時所使用的 SEQ 序列號,因為亂序的數據包將會被操作系統直接丟棄。
所以,工具需要首先監聽這個連接,然后獲取其中的序列號。再拿著這個序列號,發起模擬的 RST 數據包。你的連接就這樣斷掉了。
墻,也是這么干的。
?作者簡介:小姐姐味道 (xjjdog),一個不允許程序員走彎路的公眾號。聚焦基礎架構和Linux。十年架構,日百億流量,與你探討高并發世界,給你不一樣的味道。