Linux網絡編程socket錯誤分析

 

<!-- /* Font Definitions */ @font-face {font-family:宋體; panose-1:2 1 6 0 3 1 1 1 1 1; mso-font-alt:SimSun; mso-font-charset:134; mso-generic-font-family:auto; mso-font-pitch:variable; mso-font-signature:3 135135232 16 0 262145 0;} @font-face {font-family:"/@宋體"; panose-1:2 1 6 0 3 1 1 1 1 1; mso-font-charset:134; mso-generic-font-family:auto; mso-font-pitch:variable; mso-font-signature:3 135135232 16 0 262145 0;} /* Style Definitions */ p.MsoNormal, li.MsoNormal, div.MsoNormal {mso-style-parent:""; margin:0cm; margin-bottom:.0001pt; text-align:justify; text-justify:inter-ideograph; mso-pagination:none; font-size:10.5pt; mso-bidi-font-size:12.0pt; font-family:"Times New Roman"; mso-fareast-font-family:宋體; mso-font-kerning:1.0pt;} /* Page Definitions */ @page {mso-page-border-surround-header:no; mso-page-border-surround-footer:no;} @page Section1 {size:595.3pt 841.9pt; margin:72.0pt 90.0pt 72.0pt 90.0pt; mso-header-margin:42.55pt; mso-footer-margin:49.6pt; mso-paper-source:0; layout-grid:15.6pt;} div.Section1 {page:Section1;} -->

 

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 則是一個錯誤。

 

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

 

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

 

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.

發佈了65 篇原創文章 · 獲贊 39 · 訪問量 42萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章