拔掉網線時Socket的檢查方法


拔掉網線時Socket的檢查方法

http://blog.csdn.net/fan_hai_ping/article/details/6699650

最近在做有關於TCP采集程序時,發現在客戶端與服務器通過TCP socket進行通信的時候,如果客戶端應用程序正常或者異常退出時,服務器都可以在對應的socket通信連接上獲得響應(如返回0,或者拋出異常)。但是,如果在客戶端的網線被拔掉的情況下,那么默認情況下,服務器端需要很長的時間才會知道客戶端的網線斷掉。對於許多服務器應用程序來說,這么長的反應時間是不能允許的,在這種情況下通常使用“心跳機制”來解決類似的問題,這是一種可行的辦法。
    
    由於TCP采集程序只是通過長連接來接收消息,而不能與客戶端建立心跳機制,所以唯一可行的辦法就是設置超時機制,在非阻塞模式工作的情況下,可以通過空閑計數來判斷是否連接超時,在連接空閑情況下TCP采集程序會休眠10ms,並且空閑計數器加1,當收到數據時空閑計數器清零,因此當空閑計數達到3000次的時候,說明socket連接在30秒內沒有收到數據,此時認為連接超時,主動的斷開連接,釋放socket資源。
 如何檢查Socket是否斷開

最近在做一個TCP采集程序,使用到C/S的結構。功能比較的簡單,就是TCP采集程序作為服務器,信令采集設備作為客戶端,客戶端與服務器端之間建立長連接之后,開始發送信令報文給服務器。在服務器端使用多線程方式來處理每個客戶端的socket連接,服務器端不主動斷開鏈路,也沒有心跳機制來維護連接的狀態,客戶端發送數據的時間也是不一定的,只要有采集到信令數據時才進行發送。在客戶端socket斷開后,服務器端應該能夠知道並且釋放socket資源。

判斷socket是否已經斷開的方法是使用非阻塞的select方式進行socket檢查,步驟如下:

1)設置接收到的socket為異步方式;

2)使用select()函數測試一個socket是否可讀;

3)如果select()函數返回的值為1,但是使用recv()函數讀取的數據長度為0,那么說明該socket已經斷開。

如果recv()返回值小於等於0時,客戶端的連接已經斷開,但是還需要判斷errno是否等於EINTR。如果errno=EINTR則說明recv()函數是由於程序接收到中斷信號后返回的,socket連接應該還是正常,步應該close掉socket連接。

       注:對於阻塞socket的recv函數會在以下三種情況下返回值:

1)接收到數據時會返回;

2)程序接收到信號時返回-1,errno=EINTR;

3)Socket出現問題時,返回-1,具體的錯誤碼請查看man recv;

4)一定要養成查看man說明,內容很詳細,很有幫助。

這種方法經過長時間的測試證明是有效的,僅供大家參考。

此外,UNP卷一上有很多socket異常情況下的模擬解釋,大家可以去閱讀下。如果網絡中間有多級路由,路由當掉等很多情況出現,所以建議程序中在應用層中加入心跳(heartbeat機制)和重連來維持連接的狀態。

TCP protocol has a timer to determine if the connection is abnormally closed. But this timeout value is very long by default and if you want to check this situation as soon as possible to improve performance, the best solution is to introduce a keepalive mechanism in application protocol design.

TCP協議有一個定時器來決定連接是否被異常關閉。但是該超時時間值缺省的情況下會非常長,如果你希望盡快的檢查出這種狀態改進性能,最好的方法就是在應用程序協議設計的時候引入keepalive(保持連接)機制。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM