socket錯誤碼

轉自http://blog.csdn.net/uestc_huan/article/details/5863614
都是網上整理的資料。貼在這裏,以便查閱。

Linux網絡編程socket錯誤分析

socket錯誤碼:

EINTR: 4
阻塞的操作被取消阻塞的調用打斷。如設置了發送接收超時,就會遇到這種錯誤。
只能針對阻塞模式的socket。讀,寫阻塞的socket時,-1返回,錯誤號爲INTR。另外,如果出現EINTR即errno爲4,錯誤描述Interrupted system call,操作也應該繼續。如果recv的返回值爲0,那表明連接已經斷開,接收操作也應該結束。

ETIMEOUT:110
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不是一種錯誤。

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 則是一個錯誤。程序應該設置成Ignore這個信號。

調用write的時候, 一定要檢查 write 方法的返回值,尤其是服務端程序,當返回 -1 的時候很有可能是“connection reset by peer”(ECONNRESET 104)。如果服務程序沒有處理 SIGPIPE 信號的話,第二次程序在這條已經 close 的 socket 再次 write 時 SIGPIPE 信號就發送到 socket 關聯的 owen 進程,也就是上面說的管道破裂,而該信號的默認處理是結束進程。

EBADF:
read(..) or write(..) on a locally closed socket will return EBADF

EFAULT:
地址錯誤。

EBUSY:

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”-“服務器過早終止”錯誤。

EINVAL:
無效參數。提供的參數非法。有時也會與socket的當前狀態相關,如一個socket並沒有進入listening狀態,此時調用accept,就會產生EINVAL錯誤。

EMFILE:
打開了太多的socket。對進程或者線程而言,每種實現方法都有一個最大的可用socket數目處理,或者是全局的,或者是局部的。

EWOULDBLOCK:EAGAIN
資源暫時不可用。這個錯誤是從對非阻塞socket進行的不能立即結束的操作返回的,如當沒有數據在隊列中可以讀時,調用recv。並不是fatal錯誤,稍後操作可以被重複。調用在一個非阻塞的SOCK_STREAM socket 上調用connect時會產生這個錯誤,因爲有時連接建立必須消耗一定的時間。

ENOTCONN
在一個沒有建立連接的socket上,進行read,write操作會返回這個錯誤。出錯的原因是socket沒有標識地址。Setsoc也可能會出錯。

ECONNRESET
Connection reset by peer.
連接被遠程主機關閉。有以下幾種原因:遠程主機停止服務,重新啓動;當在執行某些操作時遇到失敗,因爲設置了“keep alive”選項,連接被關閉,一般與ENETRESET一起出現。

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

accept(2) man page 寫道
[ECONNABORTED] A connection arrived, but it was closed while waiting on the listen queue.

ENETUNREACH
網絡不可達。Socket試圖操作一個不可達的網絡。這意味着local的軟件知道沒有路由到達遠程的host。

ENETRESET
網絡重置時丟失連接。
由於設置了”keep-alive”選項,探測到一個錯誤,連接被中斷。在一個已經失敗的連接上試圖使用setsockopt操作,也會返回這個錯誤。

EINPROGRESS:
操作正在進行中。一個阻塞的操作正在執行。

ENOTSOCK:
在非socket上執行socket操作。

EDESTADDRREQ:
需要提供目的地址。
在一個socket上的操作需要提供地址。如往一個ADDR_ANY 地址上進行sendto操作會返回這個錯誤。

EMSGSIZE:
消息體太長。
發送到socket上的一個數據包大小比內部的消息緩衝區大,或者超過別的網絡限制,或是用來接收數據包的緩衝區比數據包本身小。

EPROTOTYPE
協議類型錯誤。標識了協議的Socket函數在不支持的socket上進行操作。如ARPA Internet
UDP協議不能被標識爲SOCK_STREAM socket類型。

ENOPROTOOPT
該錯誤不是一個 Socket 連接相關的錯誤。errno 給出該值可能由於,通過 getsockopt 系統調用來獲得一個套接字的當前選項狀態時,如果發現了系統不支持的選項參數就會引發該錯誤。

EPROTONOSUPPORT
不支持的協議。系統中沒有安裝標識的協議,或者是沒有實現。如函數需要SOCK_DGRAM socket,但是標識了stream protocol.。

ESOCKTNOSUPPORT
Socket類型不支持。指定的socket類型在其address family中不支持。如可選選中選項SOCK_RAW,但實現並不支持SOCK_RAW sockets。
該錯誤不是一個 Socket 連接相關的錯誤。errno 給出該值可能由於,通過 getsockopt 系統調用來獲得一個套接字的當前選項狀態時,如果發現了系統不支持的選項參數就會引發該錯誤。

EOPNOTSUPP
Operation not supported.

The attempted operation is not supported for the type of object referenced. Usually this occurs when a socket descriptor to a socket that cannot support this operation, for example, trying to accept a connection on a datagram socket.

EPFNOSUPPORT
Protocol family not supported.

The protocol family has not been configured into the system or no implementation for it exists. Has a slightly different meaning to EAFNOSUPPORT, but is interchangeable in most cases, and all Windows Sockets functions that return one of these specify EAFNOSUPPORT.

EAFNOSUPPORT
Address family not supported by protocol family.

An address incompatible with the requested protocol was used. All sockets are created with an associated “address family” (i.e. AF_INET for Internet Protocols) and a generic protocol type (i.e. SOCK_STREAM). This error will be returned if an incorrect protocol is explicitly requested in the socket call, or if an address of the wrong family is used for a socket, e.g. in sendto.

EADDRINUSE
Address already in use.

Only one usage of each socket address (protocol/IP address/port) is normally permitted. This error occurs if an application attempts to bind a socket to an IP address/port that has already been used for an existing socket, or a socket that wasn’t closed properly, or one that is still in the process of closing. For server applications that need to bind multiple sockets to the same port number, consider using setsockopt(SO_REUSEADDR). Client applications usually need not call bind at all - connect will choose an unused port automatically. When bind is called with a wild-card address (involving ADDR_ANY), a EADDRINUSE error could be delayed until the specific address is “committed.” This could happen with a call to other function later, including connect, listen, Connect or JoinLeaf.

EADDRNOTAVAIL
Cannot assign requested address.

The requested address is not valid in its context. Normally results from an attempt to bind to an address that is not valid for the local machine. This can also result from connect, sendto, Connect, JoinLeaf, or SendTo when the remote address or port is not valid for a remote machine (e.g. address or port 0).

ENETDOWN
Network is down.

A socket operation encountered a dead network. This could indicate a serious failure of the network system (i.e. the protocol stack that the WinSock DLL runs over), the network interface, or the local network itself.

ENOBUFS
No buffer space available.

An operation on a socket could not be performed because the system lacked sufficient buffer space or because a queue was full.

EISCONN
Socket is already connected.

A connect request was made on an already connected socket. Some implementations also return this error if sendto is called on a connected SOCK_DGRAM socket (For SOCK_STREAM sockets, the to parameter in sendto is ignored), although other implementations treat this as a legal occurrence.

連接過程可能出現的錯誤情況有:
(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協議來報告這些錯誤。ICMP數據包是封裝在IP數據包的數據部分中進行傳輸的,其格式如下:
類型

校驗和
數據
0 8 16 24 31
類型:指出ICMP數據包的類型。
代碼:提供ICMP數據包的進一步信息。
校驗和:提供了對整個ICMP數據包內容的校驗和。
ICMP數據包主要有以下類型:
(1) 目的地不可到達:A、目的主機未運行;B、目的地址不存在;C、路由表中沒有目的地址對應的條目,因而路由器無法找到去往目的主機的路由。
(2) 超時:路由器將接收到的IP數據包的生存時間(TTL)域減1,如果這個域的值變爲0,路由器丟棄這個IP數據包,並且發送這種ICMP消息。
(3) 參數出錯:當IP數據包中有無效域時發送。
(4) 重定向:將一條新的路徑通知主機。
(5) ECHO請求、ECHO回答:這兩條消息用語測試目的主機是否可以到達。請求者向目的主機發送ECHO請求ICMP數據包,目的主機在接收到這個ICMP數據包之後,返回ECHO回答ICMP數據包。
(6) 時戳請求、時戳回答: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分配才行。

getsockopt 和 setsockopt 還可能引發以下錯誤:

getsockopt/setsockopt(2) man page 寫道
ERRORS

The getsockopt() and setsockopt() system calls will succeed unless:

[EBADF] The argument socket is not a valid file descriptor.
[EFAULT] The address pointed to by option_value is not in a valid part of the process dress space. For getsockopt(), this error may also be returned if option_len is not in a valid part of the process address space.
[EINVAL] The option is invalid at the level indicated.
[ENOBUFS]Insufficient memory buffers are available.
[ENOPROTOOPT] The option is unknown at the level indicated.
[ENOTSOCK] The argument socket is not a socket (e.g., a plain file).

The setsockopt() system call will succeed unless:

[EDOM] The argument option_value is out of bounds.
[EISCONN]socket is already connected and a specified option cannot be set while this is the case.

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