關鍵字: tcp/ip, socket, errno
下面列出了幾個在客戶與服務進程串連中常見的幾個 Socket 錯誤,並分析了原因。後續再逐漸補充吧。
ECONNABORTED
該錯誤被描述為“software caused connection abort”,即“軟體引起的串連中止”。原因在於當服務和客戶進程在完成用於 TCP 串連的“三向交握”後,客戶 TCP 卻發送了一個 RST (複位)分節,在服務進程看來,就在該串連已由 TCP 排隊,等著服務進程調用 accept 的時候 RST 卻到達了。POSIX 規定此時的 errno 值必須 ECONNABORTED。源自 Berkeley 的實現完全在核心中處理中止的串連,服務進程將永遠不知道該中止的發生。伺服器處理序一般可以忽略該錯誤,直接再次調用accept。
C代碼
- /* Linux system */
-
- include/asm-alpha/errno.h:#define ECONNABORTED 53 /* Software caused connection
- abort */
- include/asm-generic/errno.h:#define ECONNABORTED 103 /* Software caused
- connection abort */
- include/asm-mips/errno.h:#define ECONNABORTED 130 /* Software caused connection
- abort */
accept(2) man page 寫道[ECONNABORTED] A connection arrived, but it was closed while waiting on the listen queue.
ECONNRESET
該錯誤被描述為“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”-“伺服器過早終止”錯誤。
EPIPE
錯誤被描述為“broken pipe”,即“管道破裂”,這種情況一般發生在客戶進程不理會(或未及時處理)Socket 錯誤,繼續向服務 TCP 寫入更多資料時,核心將向客戶進程發送 SIGPIPE 訊號,該訊號預設會使進程終止(此時該前台進程未進行 core dump)。結合上邊的 ECONNRESET 錯誤可知,向一個 FIN_WAIT2 狀態的服務 TCP(已 ACK 響應 FIN 分節)寫入資料不成問題,但是寫一個已接收了 RST 的 Socket 則是一個錯誤。
ETIMEDOUT
錯誤被描述為“connect time out”,即“連線逾時”,這種情況一般發生在伺服器主機崩潰。此時客戶 TCP 將在一定時間內(依具體實現)持續重發資料分節,試圖從服務 TCP 獲得一個 ACK 分節。當最終放棄嘗試後(此時伺服器未重新啟動),核心將會向客戶進程返回 ETIMEDOUT 錯誤。如果某個中間路由器判定該伺服器主機已經不可達,則一般會響應“destination unreachable”-“目的地不可達”的ICMP訊息,相應的客戶進程返回的錯誤是 EHOSTUNREACH 或ENETUNREACH。當伺服器重新啟動後,由於 TCP 狀態丟失,之前所有的串連資訊也不存在了,此時對於用戶端發來請求將回應 RST。如果客戶進程對檢測伺服器主機是否崩潰很有必要,要求即使客戶進程不主動發送資料也能檢測出來,那麼需要使用其它技術,如配置 SO_KEEPALIVE Socket 選項,或實現某些心跳函數。
作者:lzy.je
出處:http://lzy.javaeye.com
本文著作權歸作者所有,只允許以摘要和完整全文兩種形式轉載,不允許對文字進行裁剪。未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文串連,否則保留追究法律責任的權利。
// 2009.05.20 21:42 添加 ////
ENOPROTOOPT
該錯誤不是一個 Socket 串連相關的錯誤。errno 給出該值可能由於,通過 getsockopt 系統調用來獲得一個通訊端的當前選項狀態時,如果發現了系統不支援的選項參數就會引發該錯誤。
getsockopt/setsockopt(2) man page 寫道getsockopt, setsockopt -- get and set options on sockets.
#include <sys/socket.h>
int getsockopt(int socket, int level, int option_name,
void *restrict option_value, socklen_t *restrict option_len);
int setsockopt(int socket, int level, int option_name,
const void *option_value, socklen_t option_len);
Getsockopt() and setsockopt() manipulate the options associated with a socket. Options may exist at multiple protocol levels; they are always present at the uppermost "socket" level.
此外,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.