TCP之種種連接異常

出處:http://www.cnblogs.com/wanpengcoder/p/5356776.html

1. connect出錯:

(1) 若TCP客戶端沒有收到syn分節的響應,則返回ETIMEOUT錯誤;調用connect函數時,內核發送一個syn,若無響應則等待6s後再發送一個,若仍然無響應則等待24s後在發送一個,若總共等待75s後仍未收到響應則返回本錯誤;

(2) 若對客戶的syn響應是rst,則表明該服務器在我們指定的端口上沒有進程在等待與之連接,這是一種硬錯誤,客戶一收到rst馬上返回ECONNREFUSED錯誤;

(3) 若客戶發送的syn在中間的某個路由器上引發了目的不可達icmp錯誤,則認爲是一種軟錯誤。客戶主機內核保存該消息,並按照第一種情況的時間間隔繼續發送syn,咋某個規定時間後仍未收到響應,則把保存的消息作爲EHOSTUNREACH或者ENETUNREACH錯誤返回給進程;

 

2. accept返回前連接中止:

在比較忙的服務器中,在建立三次握手之後,調用accept之前,可能出現客戶端斷開連接的情況;如,三次握手之後,客戶端發送rst,然後服務器調用accept。posix指出這種情況errno設置爲CONNABORTED;

注意Berkeley實現中,沒有返回這個錯誤,而是EPROTO,同時完成三次握手的連接會從已完成隊列中移除;在這種情況下,如果我們用select監聽到有新的連接完成,但之後又被從完成隊列中刪除,此時如果調用阻塞accept就會產生阻塞;

解決辦法:

(1) 使用select監聽套接字是否有完成連接的時候,總是把這個監聽套接字設置爲非阻塞;

(2) 在後續的accept調用中忽略以下錯誤,EWOULDBLOCK(Berkeley實現,客戶中止連接), ECONNABORTED(posix實現,客戶中止連接), EPROTO(serv4實現,客戶中止連接)和EINTR(如果有信號被捕獲);

 

3. 服務器進程終止(崩潰):

在客戶端和服務器端建立連接之後,使用kill命令殺死服務器進程,進程終止會關閉所有打開的描述符,這導致了其向客戶端發送了一個FIN,而客戶端則響應了一個ack,這就完成了tcp連接終止的前半部分,只代表服務器不在發送數據了;但是客戶端並不知道服務器端已經終止了,當客戶端向服務器寫數據的時候,由於服務器進程終止,所以響應了rst,如果我們使用select等方式,能夠立即知道當前連接狀態;如下:

(1) 如果對端tcp發送數據,那麼套接字可讀,並且read返回一個大於0的值(讀入字節數);

(2) 如果對端tcp發送了fin(對端進程終止),那麼該套接字變爲可讀,並且read返回0(EOF);

(3) 如果對端tcp發送rst(對端主機崩潰並重啓),那麼該套接字變爲可讀,並且read返回-1,errno中含有確切錯誤碼;

 

4. sigpipe信號:

當一個進程向某個收到rst的套接字執行寫操作的時候,內核向該進程發送一個SIGPIPE信號,該信號的默認行爲是終止進程,因此進程必須捕獲它以免不情願的被終止;

不論進程是捕捉了該信號並從信號處理函數中返回,還是簡單忽略該信號,寫操作都講返回EPIPE錯誤;

 

5. 服務器主機崩潰:

建立連接之後,服務器主機崩潰,此時如果客戶端發送數據,會發現客戶端會在一定時間內持續重傳,視圖從服務器端收到數據的ack,當重傳時間超過指定時間後,服務器仍然沒有響應,那麼返回的是ETIMEDOUT;

 

6. 服務器主機不可達: 

建立連接之後,服務器主機未崩潰,但是由於中間路由器故障燈,判定主機或網絡不可達,此時如果客戶端發送數據,會發現客戶端會在一定時間內持續重傳,視圖從服務器端收到數據的ack,當重傳時間超過指定時間後,服務器仍然沒有響應,那麼返回的是EHOSTUNREACH或ENETUNREACH;

 

7. 服務器主機崩潰後重啓:

當服務器主機崩潰重啓後,之前所有的tcp連接丟失,此時服務器若收到來自客戶端的數據,會響應一個rst;客戶端調用read將返回一個ECONNRESET錯誤;

 

8. 服務器主機關機:

系統關機時,init進程給所有進程發送SIGTERM信號,等待固定的時間,然後給所有仍在運行的進程發送SIGKILL信號,我們的進程會被SIGTERM或者SIGKILL信號終止,所以與前面服務器進程終止相同,進程關閉所有描述符,併發送fin,完成服務器端的半關閉;

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章