您的位置:首页 > 其它

几个常见的 Socket 连接错误及原因[转]

2017-01-10 10:04 471 查看
下面列出了几个在客户与服务进程连接中常见的几个 Socket 错误,并分析了原因。后续再逐渐补充吧。


ECONNABORTED

          该错误被描述为“software caused connection abort”,即“软件引起的连接中止”。原因在于当服务和客户进程在完成用于 TCP 连接的“三次握手”后,客户 TCP 却发送了一个 RST (复位)分节,在服务进程看来,就在该连接已由 TCP 排队,等着服务进程调用 accept 的时候 RST 却到达了。POSIX 规定此时的 errno 值必须 ECONNABORTED。源自
Berkeley 的实现完全在内核中处理中止的连接,服务进程将永远不知道该中止的发生。服务器进程一般可以忽略该错误,直接再次调用accept。

C代码 < type="application/x-shockwave-flash" width="14" height="15" src="http://lzy.javaeye.com/javascripts/syntaxhighlighter/clipboard_new.swf" src="http://lzy.javaeye.com/javascripts/syntaxhighlighter/clipboard_new.swf" flashvars="clipboard= include/asm-alpha/errno.h:#define
ECONNABORTED 53 include/asm-generic/errno.h:#define ECONNABORTED 103 include/asm-mips/errno.h:#define ECONNABORTED 130 " quality="high" allowscriptaccess="always" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer"
width="14" height="15">
   
  
include/asm-alpha/errno.h:#define ECONNABORTED 53    
include/asm-generic/errno.h:#define ECONNABORTED 103   
include/asm-mips/errno.h:#define ECONNABORTED 130    

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.

// 2009.12.21 16:21 添加 ////

          一定要检查 write 方法的返回值,尤其是服务端程序,当返回 -1 的时候很有可能是“connection reset by peer”(ECONNRESET 104)。如果服务程序没有处理 SIGPIPE 信号的话,第二次程序在这条已经 close 的 socket 再次 write 时 SIGPIPE 信号就发送到 socket 关联的 owen 进程,也就是上面说的管道破裂,而该信号的默认处理是结束进程。今天不小心又因为这个浪费了两小时,在客户程序连续通信的时候,直接结束客户进程就造成服
务进程也同时退出。开来还是太粗心。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: