背景:前些天團隊在進行終端設備和服務器端長鏈接業務的測試時,發現了這麼一個狀況:在拔掉設備端的網線後,再插上網線,有時能夠繼續正常的進行長接連請求,並且用的仍是拔掉網線以前的那個長鏈接。可是有時卻不能繼續正常的長鏈接請求,須要從新創建一個新的長鏈接。讓我尤感詫異的是第一種網線斷開再插上後長鏈接能夠恢復的狀況,完全顛覆了我一直抱有的一個所謂的「物理鏈接」的觀念。究竟怎麼回事,咱們來探個究竟。編程
首先說說我本身發明的「物理鏈接」這個名詞,無論怎麼說我都是一個網絡編程的"老手"。常常會給新人和其餘有問題諮詢個人同事灌輸一個觀念,只要網線拔掉了,說明物理鏈接都斷了,更別提邏輯上的TCP長鏈接,再插上網線也只能再創建一個新的鏈接來繼續進行請求。我作個簡單的比喻:我理解的TCP長鏈接比如之前咱們用的有線電話,甲和乙通話的過程當中,假若其中一人的電話線被拔掉了,鏈接就完全斷了。即便再插上電話線也不可能自動恢復通話,咱們不得不從新撥通。服務器
發現了插上網線後鏈接還會恢復的狀況,我起初覺得是簡單的TCP套接字複用的狀況,可是發現設備端並未編寫自動重連的邏輯,這就太讓我好奇和疑慮了。因而我找了一個同事配合我進行了屢次測試,發現了拔掉網線後針對此TCP長鏈接可能會出現的 兩種狀況。網絡
首先作下鋪墊,作過網絡編程的朋友應該都知道這麼一個狀況測試
當客戶端與服務器創建起正常的TCP鏈接後,若是客戶主機網線斷開、電源掉電、或系統崩潰,服務器進程將永遠不會知道(經過咱們經常使用的select,epoll監測不到斷開或錯誤事件),若是不主動處理或重啓系統的話對於服務端來講會一直維持着這個鏈接,任憑服務端進程如何望穿秋水,也永遠再等不到客戶端的任何迴應。這種狀況就是半開鏈接,浪費了服務器端可用的文件描述符。操作系統
說明網線斷開對端是不能作任何感知的,除非咱們配置操做系統的SO_KEEPALIVE選項,或者進行應用層心跳檢測。請參考文章《網絡編程釋疑之:TCP半開鏈接的處理》。code
若是網線斷開的時間短暫,在SO_KEEPALIVE設定的探測時間間隔內,而且兩端在此期間沒有任何針對此長鏈接的網絡操做。當連上網線後此TCP鏈接能夠自動恢復,繼續進行正常的網絡操做。blog
若是網線斷開的時間很長,超出了SO_KEEPALIVE設定的探測時間間隔,或者兩端期間在此有了任何針對此長鏈接的網絡操做。當連上網線時就會出現ETIMEDOUT或者ECONNRESET的錯誤。你必須從新創建一個新的長鏈接進行網絡操做。進程
這件過後,我不再敢隨便發明名詞了,嗚嗚......事件