生活随笔
收集整理的這篇文章主要介紹了
网络编程释疑之:TCP半开连接的处理
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
熟悉基于TCP協(xié)議進(jìn)行l(wèi)inux高性能、高并發(fā)服務(wù)端編程的朋友肯定應(yīng)該知道每個文件描述符及其所占的資源對并發(fā)量的影響。在這種7*24甚至*365不間斷運(yùn)行的服務(wù)器上,一個描述符被浪費(fèi),兩個被浪費(fèi)...如果被浪費(fèi)的多了,那還何談高并發(fā),高性能。除去文件描述被正常占用的情況外,是什么導(dǎo)致了我們可用的文件描述符越來越少呢?
什么是半開連接?
當(dāng)客戶端與服務(wù)器建立起正常的TCP連接后,如果客戶主機(jī)掉線(網(wǎng)線斷開)、電源掉電、或系統(tǒng)崩潰,服務(wù)器進(jìn)程將永遠(yuǎn)不會知道(通過我們常用的select,epoll監(jiān)測不到斷開或錯誤事件),如果不主動處理或重啟系統(tǒng)的話對于服務(wù)端來說會一直維持著這個連接,任憑服務(wù)端進(jìn)程如何望穿秋水,也永遠(yuǎn)再等不到客戶端的任何回應(yīng)。這種情況就是半開連接,浪費(fèi)了服務(wù)器端可用的文件描述符。
如何處理?
熟悉套接字通用選項的朋友一定已經(jīng)有了想法。TCP套接字不是有個保持存活選項SO_KEEPALIVE嘛,如果在兩個小時之內(nèi)在該套接字的任何一個方向上都沒數(shù)據(jù)交換,TCP就自動給對端發(fā)送一個保持存活探測分節(jié),如果此TCP探測分節(jié)的響應(yīng)為RST,說明對端已經(jīng)崩潰且已經(jīng)重新啟動,該套接字的待處理錯誤被置為ECONNRESET,套接字本身則被關(guān)閉。如果沒有對此TCP探測分節(jié)的任何響應(yīng),該套接字的處理錯誤就被置為ETIMEOUT,套接字本身則被關(guān)閉。
確實,這個選項確實可以處理我們前面遇到的TCP半開連接的問題,但是默認(rèn)兩小時間隔探測的實時性是不是差了些呢?當(dāng)然,我們可以通過修改內(nèi)核參數(shù)改小時間間隔,完美了吧?但是必須注意的是大多數(shù)內(nèi)核是基于整個內(nèi)核維護(hù)這些時間參數(shù)的,而不是基于每個套接字維護(hù)的,因此如果把無活動周期從兩小時改為(比如)2分鐘,那將影響到該主機(jī)上所有開啟了此選項的套接字。我想大家都不會愿意承擔(dān)服務(wù)器端的這種不確定性吧。另外,心跳除了說明應(yīng)用程序還活著(進(jìn)程存在,網(wǎng)絡(luò)暢通),更重要的是表明應(yīng)用程序能正常工作。而SO_KEEPALIVE由操作系統(tǒng)負(fù)責(zé)探查,即便是進(jìn)程死鎖或有其他異常,操作系統(tǒng)也會正常收發(fā)TCP keepalive消息,而對方無法得知這一異常。
沒關(guān)系,其實我們可以在應(yīng)用層模擬SO_KEEPALIVE的方式,用心跳包來模擬保活探測分節(jié)。由于服務(wù)器通常要承擔(dān)成千上萬的并發(fā)連接,所以肯定是由客戶端在應(yīng)用層進(jìn)行心跳來模擬保活探測分節(jié),客戶端多次收不到服務(wù)器的響應(yīng)時可終止此TCP連接,而服務(wù)端可監(jiān)測客戶端的心跳包,若在一定時間間隔內(nèi)未收到任何來自客戶端的心跳包則可以終止此TCP連接,這樣就有效避免了TCP半開連接的情況。
參考書籍:
《UNIX網(wǎng)絡(luò)編程:卷1》
《Linux多線程服務(wù)端編程》
總結(jié)
以上是生活随笔為你收集整理的网络编程释疑之:TCP半开连接的处理的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。