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万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章