linux網絡編程常見socket錯誤分析

jopen 11年前發布 | 66K 次閱讀 Linux

常見socket錯誤碼

EINTR:
阻塞的操作被取消阻塞的調用打斷。如設置了發送接收超時,就會遇到這種錯誤。
只能針對阻塞模式的socket。讀,寫阻塞的socket時,-1返回,錯誤號為INTR。另外,如果出現EINTR即errno為4,錯誤描述 Interrupted system call,操作也應該繼續。如果recv的返回值為0,那表明連接已經斷開,接收操作也應該結束。
 
ETIMEOUT:
1、操作超時。一般設置了發送接收超時,遇到網絡繁忙的情況,就會遇到這種錯誤。
2、服務器做了讀數據做了超時限制,讀時發生了超時。
3、錯誤被描述為“connect time out”,即“連接超時”,這種情況一般發生在服務器主機崩潰。此時客戶 TCP 將在一定時間內(依具體實現)持續重發數據分節,試圖從服務 TCP 獲得一個 ACK 分節。當最終放棄嘗試后(此時服務器未重新啟動),內核將會向客戶進程返回 ETIMEDOUT 錯誤。如果某個中間路由器判定該服務器主機已經不可達,則一般會響應“destination unreachable”-“目的地不可達”的ICMP消息,相應的客戶進程返回的錯誤是 EHOSTUNREACH 或ENETUNREACH。當服務器重新啟動后,由于 TCP 狀態丟失,之前所有的連接信息也不存在了,此時對于客戶端發來請求將回應 RST。如果客戶進程對檢測服務器主機是否崩潰很有必要,要求即使客戶進程不主動發送數據也能檢測出來,那么需要使用其它技術,如配置 SO_KEEPALIVE Socket 選項,或實現某些心跳函數。
 
EAGAIN:
1、Send返回值小于要發送的數據數目,會返回EAGAIN和EINTR。
2、recv 返回值小于請求的長度時說明緩沖區已經沒有可讀數據,但再讀不一定會觸發EAGAIN,有可能返回0表示TCP連接已被關閉。
3、當socket是非阻塞時,如返回此錯誤,表示寫緩沖隊列已滿,可以做延時后再重試.
4、在Linux進行非阻塞的socket接收數據時經常出現Resource temporarily unavailable,errno代碼為11(EAGAIN),表明在非阻塞模式下調用了阻塞操作,在該操作沒有完成就返回這個錯誤,這個錯誤不會破壞 socket的同步,不用管它,下次循環接著recv就可以。對非阻塞socket而言,EAGAIN不是一種錯誤。
 
EWOULDBLOCK:EAGAIN (POSIX.1-2001 allows)
資源暫時不可用。這個錯誤是從對非阻塞socket進行的不能立即結束的操作返回的,如當沒有數據在隊列中可以讀時,調用recv。并不是fatal錯誤,稍后操作可以被重復。調用在一個非阻塞的SOCK_STREAM socket 上調用connect時會產生這個錯誤,因為有時連接建立必須消耗一定的時間。

EPIPE:
1、Socket 關閉,但是socket號并沒有置-1。繼續在此socket上進行send和recv,就會返回這種錯誤。這個錯誤會引發SIGPIPE信號,系統會將產生此EPIPE錯誤的進程殺死。所以,一般在網絡程序中,首先屏蔽此消息,以免發生不及時設置socket進程被殺死的情況。
2、write(..) on a socket that has been closed at the other end will cause a SIGPIPE.
3、錯誤被描述為“broken pipe”,即“管道破裂”,這種情況一般發生在客戶進程不理會(或未及時處理)Socket 錯誤,繼續向服務 TCP 寫入更多數據時,內核將向客戶進程發送 SIGPIPE 信號,該信號默認會使進程終止(此時該前臺進程未進行 core dump)。結合上邊的 ECONNRESET 錯誤可知,向一個 FIN_WAIT2 狀態的服務 TCP(已 ACK 響應 FIN 分節)寫入數據不成問題,但是寫一個已接收了 RST 的 Socket 則是一個錯誤。
 
ECONNREFUSED:
1、拒絕連接。一般發生在連接建立時。
拔服務器端網線測試,客戶端設置keep alive時,recv較快返回0, 先收到ECONNREFUSED (Connection refused)錯誤碼,其后都是ETIMEOUT。
2、an error returned from connect(), so it can only occur in a client (if a client is defined as the party that initiates the connection
 
ECONNRESET:
1、在客戶端服務器程序中,客戶端異常退出,并沒有回收關閉相關的資源,服務器端會先收到ECONNRESET錯誤,然后收到EPIPE錯誤。
2、連接被遠程主機關閉。有以下幾種原因:遠程主機停止服務,重新啟動;當在執行某些操作時遇到失敗,因為設置了“keep alive”選項,連接被關閉,一般與ENETRESET一起出現。
3、遠程端執行了一個“hard”或者“abortive”的關閉。應用程序應該關閉socket,因為它不再可用。當執行在一個UDP socket上時,這個錯誤表明前一個send操作返回一個ICMP“port unreachable”信息。
4、如果client關閉連接,server端的select并不出錯(不返回-1,使用select對唯一一個socket進行non- blocking檢測),但是寫該socket就會出錯,用的是send.錯誤號:ECONNRESET.讀(recv)socket并沒有返回錯誤。
5、該錯誤被描述為“connection reset by peer”,即“對方復位連接”,這種情況一般發生在服務進程較客戶進程提前終止。當服務進程終止時會向客戶 TCP 發送 FIN 分節,客戶 TCP 回應 ACK,服務 TCP 將轉入 FIN_WAIT2 狀態。此時如果客戶進程沒有處理該 FIN (如阻塞在其它調用上而沒有關閉 Socket 時),則客戶 TCP 將處于 CLOSE_WAIT 狀態。當客戶進程再次向 FIN_WAIT2 狀態的服務 TCP 發送數據時,則服務 TCP 將立刻響應 RST。一般來說,這種情況還可以會引發另外的應用程序異常,客戶進程在發送完數據后,往往會等待從網絡IO接收數據,很典型的如 read 或 readline 調用,此時由于執行時序的原因,如果該調用發生在 RST 分節收到前執行的話,那么結果是客戶進程會得到一個非預期的 EOF 錯誤。此時一般會輸出“server terminated prematurely”-“服務器過早終止”錯誤。

ECONNABORTED:
1、軟件導致的連接取消。一個已經建立的連接被host方的軟件取消,原因可能是數據傳輸超時或者是協議錯誤。
2、該錯誤被描述為“software caused connection abort”,即“軟件引起的連接中止”。原因在于當服務和客戶進程在完成用于 TCP 連接的“三次握手”后,客戶 TCP 卻發送了一個 RST (復位)分節,在服務進程看來,就在該連接已由 TCP 排隊,等著服務進程調用 accept 的時候 RST 卻到達了。POSIX 規定此時的 errno 值必須 ECONNABORTED。源自 Berkeley 的實現完全在內核中處理中止的連接,服務進程將永遠不知道該中止的發生。服務器進程一般可以忽略該錯誤,直接再次調用accept。
當TCP協議接收到RST數據段,表示連接出現了某種錯誤,函數read將以錯誤返回,錯誤類型為ECONNERESET。并且以后所有在這個套接字上的讀操作均返回錯誤。錯誤返回時返回值小于0。

連接過程出錯分析

(1) 如果客戶機TCP協議沒有接收到對它的SYN數據段的確認,函數以錯誤返回,錯誤類型為ETIMEOUT。通常TCP協議在發送SYN數據段失敗之后,會多次發送SYN數據段,在所有的發送都高中失敗之后,函數以錯誤返回。
注:SYN(synchronize)位:請求連接。TCP用這種數據段向對方TCP協議請求建立連接。在這個數據段中,TCP協議將它選擇的初始序列號通知對方,并且與對方協議協商最大數據段大小。SYN數據段的序列號為初始序列號,這個SYN數據段能夠被確認。當協議接收到對這個數據段的確認之后,建立TCP連接。
(2) 如果遠程TCP協議返回一個RST數據段,函數立即以錯誤返回,錯誤類型為ECONNREFUSED。當遠程機器在SYN數據段指定的目的端口號處沒有服務進程在等待連接時,遠程機器的TCP協議將發送一個RST數據段,向客戶機報告這個錯誤。客戶機的TCP協議在接收到RST數據段后不再繼續發送SYN 數據段,函數立即以錯誤返回。
注:RST(reset)位:表示請求重置連接。當TCP協議接收到一個不能處理的數據段時,向對方TCP協議發送這種數據段,表示這個數據段所標識的連接出現了某種錯誤,請求TCP協議將這個連接清除。有3種情況可能導致TCP協議發送RST數據段:(1)SYN數據段指定的目的端口處沒有接收進程在等待;(2)TCP協議想放棄一個已經存在的連接;(3)TCP接收到一個數據段,但是這個數據段所標識的連接不存在。接收到RST數據段的TCP協議立即將這條連接非正常地斷開,并向應用程序報告錯誤。
(3) 如果客戶機的SYN數據段導致某個路由器產生“目的地不可到達”類型的ICMP消息,函數以錯誤返回,錯誤類型為EHOSTUNREACH或 ENETUNREACH。通常TCP協議在接收到這個ICMP消息之后,記錄這個消息,然后繼續幾次發送SYN數據段,在所有的發送都告失敗之后,TCP 協議檢查這個ICMP消息,函數以錯誤返回。
注:ICMP:Internet 消息控制協議。Internet的運行主要是由Internet的路由器來控制,路由器完成IP數據包的發送和接收,如果發送數據包時發生錯誤,路由器使用 ICMP協議來報告這些錯誤。
調用函數connect的過程中,當客戶機TCP協議發送了SYN數據段的確認之后,TCP狀態由CLOSED狀態轉為SYN_SENT狀態,在接收到對 SYN數據段的確認之后,TCP狀態轉換成ESTABLISHED狀態,函數成功返回。如果調用函數connect失敗,應該用close關閉這個套接字描述符,不能再次使用這個套接字描述符來調用函數connect。
 
connect函數的出錯處理:
(1)ETIMEOUT-connection timed out 目的主機不存在,沒有返回任何相應,例如主機關閉
(2)ECONNREFUSED-connection refused(硬錯)到達目的主機后,由于各種原因建立不了連接,主機返回RST(復位)響應,例如主機監聽進程未啟用,tcp取消連接等
(3)EHOSTTUNREACH-no route to host(軟錯)路由上引發了一個目的地不可達的ICMP錯誤
 
其中(1)(3),客戶端會進行定時多次重試,一定次數后才返回錯誤。另外,當connect連接失敗時,sockfd套接口不可用,必須關閉后重新socket分配才行。

原文地址:http://blog.csdn.net/nellson/article/details/5669935

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!