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 则 是 一 个 错 误
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.