熟悉基於tcp協議進行linux高效能、高併發服務端程式設計的朋友肯定應該知道每個檔案描述符及其所佔的資源對併發量的影響。在這種7*24甚至*365不間斷執行的伺服器上,乙個描述符被浪費,兩個被浪費...如果被浪費的多了,那還何談高併發,高效能。除去檔案描述被正常占用的情況外,是什麼導致了我們可用的檔案描述符越來越少呢?
什麼是半開連線?
當客戶端與伺服器建立起正常的tcp連線後,如果客戶主機掉線(網線斷開)、電源掉電、或系統崩潰,伺服器程序將永遠不會知道(通過我們常用的select,epoll監測不到斷開或錯誤事件),如果不主動處理或重啟系統的話對於服務端來說會一直維持著這個連線,任憑服務端程序如何望穿秋水,也永遠再等不到客戶端的任何回應。這種情況就是半開連線,浪費了伺服器端可用的檔案描述符。
如何處理?
熟悉套接字通用選項的朋友一定已經有了想法。tcp套接字不是有個保持存活選項so_keepalive嘛,如果在兩個小時之內在該套接字的任何乙個方向上都沒資料交換,tcp就自動給對端傳送乙個保持存活探測分節,如果此tcp探測分節的響應為rst,說明對端已經崩潰且已經重新啟動,該套接字的待處理錯誤被置為econnreset,套接字本身則被關閉。如果沒有對此tcp探測分節的任何響應,該套接字的處理錯誤就被置為etimeout,套接字本身則被關閉。
確實,這個選項確實可以處理我們前面遇到的tcp半開連線的問題,但是預設兩小時間隔探測的實時性是不是差了些呢?當然,我們可以通過修改核心引數改小時間間隔,完美了吧?但是必須注意的是大多數核心是基於整個核心維護這些時間引數的,而不是基於每個套接字維護的,因此如果把無活動週期從兩小時改為(比如)2分鐘,那將影響到該主機上所有開啟了此選項的套接字。我想大家都不會願意承擔伺服器端的這種不確定性吧。另外,心跳除了說明應用程式還活著(程序存在,網路暢通),更重要的是表明應用程式能正常工作。而so_keepalive由作業系統負責探查,即便是程序死鎖或有其他異常,作業系統也會正常收發tcp keepalive訊息,而對方無法得知這一異常。
沒關係,其實我們可以在應用層模擬so_keepalive的方式,用心跳包來模擬保活探測分節。由於伺服器通常要承擔成千上萬的併發連線,所以肯定是由客戶端在應用層進行心跳來模擬保活探測分節,客戶端多次收不到伺服器的響應時可終止此tcp連線,而服務端可監測客戶端的心跳包,若在一定時間間隔內未收到任何來自客戶端的心跳包則可以終止此tcp連線,這樣就有效避免了tcp半開連線的情況。
參考書籍:
《unix網路程式設計:卷1》
《linux多執行緒服務端程式設計》
yaocoder
網路程式設計釋疑之 TCP半開連線的處理
熟悉基於tcp協議進行linux高效能 高併發服務端程式設計的朋友肯定應該知道每個檔案描述符及其所佔的資源對併發量的影響。在這種7 24甚至 365不間斷執行的伺服器上,乙個描述符被浪費,兩個被浪費.如果被浪費的多了,那還何談高併發,高效能。除去檔案描述被正常占用的情況外,是什麼導致了我們可用的檔案...
網路程式設計釋疑之 TCP半開連線的處理
熟悉基於tcp協議進行linux高效能 高併發服務端程式設計的朋友肯定應該知道每個檔案描述符及其所佔的資源對併發量的影響。在這種7 24甚至 365不間斷執行的伺服器上,乙個描述符被浪費,兩個被浪費.如果被浪費的多了,那還何談高併發,高效能。除去檔案描述被正常占用的情況外,是什麼導致了我們可用的檔案...
網路程式設計釋疑之 TCP半開連線的處理
熟悉基於tcp協議進行linux高效能 高併發服務端程式設計的朋友肯定應該知道每個檔案描述符及其所佔的資源對併發量的影響。在這種7 24甚至 365不間斷執行的伺服器上,乙個描述符被浪費,兩個被浪費.如果被浪費的多了,那還何談高併發,高效能。除去檔案描述被正常占用的情況外,是什麼導致了我們可用的檔案...