connect 是 errno 为111 115 101 22 错误分析

本文深入解析了Linux的网络错误码表及其在Socket操作中的常见问题,包括参数错误、网络不可达、链接被拒绝等,并提供了详细的错误码解释和处理建议。

22:参数错误,比如ip地址不合法,没有目标端口等

101:网络不可达,比如不能ping通

111:链接被拒绝,比如目标关闭链接等

115:当链接设置为非阻塞时,目标没有及时应答,返回此错误,socket可以继续使用

 

附录:Linux的错误码表(errno table)

_ 124 EMEDIUMTYPE_ Wrong medium type
_ 123 ENOMEDIUM__ No medium found
_ 122 EDQUOT___  Disk quota exceeded
_ 121 EREMOTEIO__ Remote I/O error
_ 120 EISNAM___  Is a named type file
_ 119 ENAVAIL___ No XENIX semaphores available
_ 118 ENOTNAM___ Not a XENIX named type file
_ 117 EUCLEAN___ Structure needs cleaning
_ 116 ESTALE___  Stale NFS file handle
_ 115 EINPROGRESS  +Operation now in progress
_ 114 EALREADY__  Operation already in progress
_ 113 EHOSTUNREACH  No route to host
_ 112 EHOSTDOWN__ Host is down
_ 111 ECONNREFUSED  Connection refused
_ 110 ETIMEDOUT_  +Connection timed out
_ 109 ETOOMANYREFS  Too many references: cannot splice
_ 108 ESHUTDOWN__ Cannot send after transport endpoint shutdown
_ 107 ENOTCONN__  Transport endpoint is not connected
_ 106 EISCONN___ Transport endpoint is already connected
_ 105 ENOBUFS___ No buffer space available
_ 104 ECONNRESET_  Connection reset by peer
_ 103 ECONNABORTED  Software caused connection abort
_ 102 ENETRESET__ Network dropped connection on reset
_ 101 ENETUNREACH_ Network is unreachable
_ 100 ENETDOWN__  Network is down
_  99 EADDRNOTAVAIL Cannot assign requested address
_  98 EADDRINUSE_  Address already in use
_  97 EAFNOSUPPORT  Address family not supported by protocol
_  96 EPFNOSUPPORT  Protocol family not supported
_  95 EOPNOTSUPP_  Operation not supported
_  94 ESOCKTNOSUPPORT Socket type not supported
_  93 EPROTONOSUPPORT Protocol not supported
_  92 ENOPROTOOPT_ Protocol not available
_  91 EPROTOTYPE_  Protocol wrong type for socket
_  90 EMSGSIZE__ +Message too long
_  89 EDESTADDRREQ  Destination address required
_  88 ENOTSOCK__  Socket operation on non-socket
_  87 EUSERS___  Too many users
_  86 ESTRPIPE__  Streams pipe error
_  85 ERESTART__  Interrupted system call should be restarted
_  84 EILSEQ___  Invalid or incomplete multibyte or wide character
_  83 ELIBEXEC__  Cannot exec a shared library directly
_  82 ELIBMAX___ Attempting to link in too many shared libraries
_  81 ELIBSCN___ .lib section in a.out corrupted
_  80 ELIBBAD___ Accessing a corrupted shared library
_  79 ELIBACC___ Can not access a needed shared library
_  78 EREMCHG___ Remote address changed
_  77 EBADFD___  File descriptor in bad state
_  76 ENOTUNIQ__  Name not unique on network
_  75 EOVERFLOW__ Value too large for defined data type
_  74 EBADMSG__  +Bad message
_  73 EDOTDOT___ RFS specific error
_  72 EMULTIHOP__ Multihop attempted
_  71 EPROTO___  Protocol error
_  70 ECOMM____ Communication error on send
_  69 ESRMNT___  Srmount error
_  68 EADV____  Advertise error
_  67 ENOLINK___ Link has been severed
_  66 EREMOTE___ Object is remote
_  65 ENOPKG___  Package not installed
_  64 ENONET___  Machine is not on the network
_  63 ENOSR____ Out of streams resources
_  62 ETIME____ Timer expired
_  61 ENODATA___ No data available
_  60 ENOSTR___  Device not a stream
_  59 EBFONT___  Bad font file format
_  57 EBADSLT___ Invalid slot
_  56 EBADRQC___ Invalid request code
_  55 ENOANO___  No anode
_  54 EXFULL___  Exchange full
_  53 EBADR____ Invalid request descriptor
_  52 EBADE____ Invalid exchange
_  51 EL2HLT___  Level 2 halted
_  50 ENOCSI___  No CSI structure available
_  49 EUNATCH___ Protocol driver not attached
_  48 ELNRNG___  Link number out of range
_  47 EL3RST___  Level 3 reset
_  46 EL3HLT___  Level 3 halted
_  45 EL2NSYNC__  Level 2 not synchronized
_  44 ECHRNG___  Channel number out of range
_  43 EIDRM____ Identifier removed
_  42 ENOMSG___  No message of desired type
_  40 ELOOP____ Too many levels of symbolic links
_  39 ENOTEMPTY_  +Directory not empty
_  38 ENOSYS___ +Function not implemented
_  37 ENOLCK___ +No locks available
_  36 ENAMETOOLONG +File name too long
_  35 EDEADLK__  +Resource deadlock avoided
_  34 ERANGE___ +Numerical result out of range
_  33 EDOM____ +Numerical argument out of domain
_  32 EPIPE___  +Broken pipe
_  31 EMLINK___ +Too many links
_  30 EROFS___  +Read-only file system
_  29 ESPIPE___ +Illegal seek
_  28 ENOSPC___ +No space left on device
_  27 EFBIG___  +File too large
_  26 ETXTBSY___ Text file busy
_  25 ENOTTY___ +Inappropriate ioctl for device
_  24 EMFILE___ +Too many open files
_  23 ENFILE___ +Too many open files in system
_  22 EINVAL___ +Invalid argument
_  21 EISDIR___ +Is a directory
_  20 ENOTDIR__  +Not a directory
_  19 ENODEV___ +No such device
_  18 EXDEV___  +Invalid cross-device link
_  17 EEXIST___ +File exists
_  16 EBUSY___  +Device or resource busy
_  15 ENOTBLK___ Block device required
_  14 EFAULT___ +Bad address
_  13 EACCES___ +Permission denied
_  12 ENOMEM___ +Cannot allocate memory
_  11 EAGAIN___ +Resource temporarily unavailable
_  10 ECHILD___ +No child processes
__ 9 EBADF___  +Bad file descriptor
__ 8 ENOEXEC__  +Exec format error
__ 7 E2BIG___  +Argument list too long
__ 6 ENXIO___  +No such device or address
__ 5 EIO____  +Input/output error
__ 4 EINTR___  +Interrupted system call
__ 3 ESRCH___  +No such process
__ 2 ENOENT___ +No such file or directory
__ 1 EPERM___  +Operation not permitted
#_  0 --_____  Success

 

附录参考 http://fanqiang.chinaunix.net/a4/b7/20010913/0900001283.html

摘要:

讨论关于利用select()检测对方Socket关闭的问题: 
 
仍然是本地Socket有东东可读,因为对方Socket关闭时,会发一个关闭连接 
通知报文,会马上被select()检测到的。关于TCP的连接(三次握手)和关 
闭(二次握手)机制,敬请参考有关TCP/IP的书籍。 
 
不知是什么原因,UNIX好象没有提供通知进程关于Socket或Pipe对方关闭的 
信号,也可能是cpu所知有限。总之,当对方关闭,一执行recv()或read(), 
马上回返回-1,此时全局变量errno的值是115,相应的sys_errlist[errno] 
为"Connect refused"(请参考/usr/include/sys/errno.h)。所以,在上 
篇的for(;;)...select()程序块中,当有东西可读时,一定要检查recv()或 
read()的返回值,返回-1时要作出关断本地Socket的处理,否则select()会 
一直认为有东西读,其结果曾几令cpu伤心欲断针脚。不信你可以试试:不检 
查recv()返回结果,且将收到的东东(实际没收到)写至标准输出... 
在有名管道的编程中也有类似问题出现。具体处理详见拙作:发布一个有用 
的Socket客户方原码。 
 
至于主动写Socket时对方突然关闭的处理则可以简单地捕捉信号SIGPIPE并作 
出相应关断本地Socket等等的处理。SIGPIPE的解释是:写入无读者方的管道。 
在此不作赘述,请详man signal。 
 
以上是cpu在作tcp/ip数据传输实验积累的经验,若有错漏,请狂炮击之。 
 
唉,昨天在hacker区被一帮孙子轰得差点儿没短路。ren cpu(奔腾的心) z80 
 
补充关于select在异步(非阻塞)connect中的应用,刚开始搞socket编程的时候 
我一直都用阻塞式的connect,非阻塞connect的问题是由于当时搞proxy scan 
而提出的呵呵 
通过在网上与网友们的交流及查找相关FAQ,总算知道了怎么解决这一问题.同样 
用select可以很好地解决这一问题.大致过程是这样的: 
 
1.将打开的socket设为非阻塞的,可以用fcntl(socket, F_SETFL, O_NDELAY)完 
成(有的系统用FNEDLAY也可). 
 
2.发connect调用,这时返回-1,但是errno被设为EINPROGRESS,意即connect仍旧 
在进行还没有完成. 
 
3.将打开的socket设进被监视的可写(注意不是可读)文件集合用select进行监视, 
如果可写,用 
        getsockopt(socket, SOL_SOCKET, SO_ERROR, &error, sizeof(int)); 
来得到error的值,如果为零,则connect成功. 
 
在许多unix版本的proxyscan程序你都可以看到类似的过程,另外在solaris精华 
区->编程技巧中有一个通用的带超时参数的connect模块. 

<think>嗯,用户现在想了解非阻塞connect中出现的EALREADY错误的意义,以及connect函数的用法和底层实现原理。首先,我需要回忆一下非阻塞connect的处理流程。当套接字设置为非阻塞时,调用connect会立即返回,如果连接不能立即建立,通常会返回-1,并且errno被设置为EINPROGRESS。这时候应用程序需要使用select、poll或者epoll来等待连接完成。 不过用户提到的是EALREADY,这个错误码出现在非阻塞connect的情况下。根据之前的知识,EALREADY表示之前的连接请求已经在进行中,用户再次调用connect的时候,之前的请求还没有完成,所以会报这个错误。也就是说,当套接字已经处于连接进行中的状态(比如SYN_SENT),再次调用connect就会触发EALREADY。接下来需要结合用户提供的引用内容。引用[1]提到了Linux内核中TCP连接的状态管理和非阻塞处理,这可能涉及到连接过程中的状态转换。引用[3]中的reqsk_queue_remove函数可能涉及到连接队列的处理,而引用[4]中的tcp_finish_connect函数设置了TCP_ESTABLISHED状态,并唤醒等待的进程,这可能与非阻塞connect完成后的处理有关。 用户还提到了connect函数的底层实现原理,需要结合三次握手和内核状态转换来解释。在非阻塞模式下,内核在发送SYN后,不会阻塞进程,而是让进程继续执行,之后通过检查套接字的可写性来判断连接是否完成。如果在此期间再次调用connect,内核会检查当前套接字的状态,如果已经是SYN_SENT或SYN_RECEIVED,就会返回EALREADY错误。关于EALREADY的底层实现,需要查看内核源码中connect的处理逻辑。当应用程序调用connect时,内核会检查套接字的当前状态。如果套接字已经处于连接进行中的状态,比如SYN_SENT,那么再次调用connect就会触发这个错误。这可能在inet_stream_connect或者__inet_stream_connect函数中处理,这里需要检查状态是否允许再次连接。另外,引用[4]中的tcp_finish_connect函数负责将套接字状态设置为ESTABLISHED,并唤醒等待的进程。这和非阻塞connect完成后的处理流程相关,当三次握手完成后,内核会改变套接字状态,并通知应用程序。 用户可能的问题是如何处理EALREADY错误。正确的做法是避免在非阻塞connect已经进行中的情况下重复调用connect,而应该等待套接字可写,然后通过getsockopt来检查连接是否成功。此外,用户之前的问题涉及到了connect的用法和底层原理,现在需要将EALREADY整合进去,说明其产生的原因和解决方法。需要确保回答结构清晰,分点解释错误意义、触发场景、内核处理逻辑,以及编程建议。可能还需要引用用户提供的引用内容中的相关部分,比如引用[1]中的分层设计和状态管理,引用[3]中的队列操作,引用[4]中的状态设置和唤醒机制,来支持对EALREADY的解释和connect底层原理的说明。最后,生成相关问题时要围绕非阻塞connect错误处理、内核实现细节、性能优化等方面展开,确保问题具有连续性和深度。</think>### 非阻塞connect中EALREADY的意义与原理分析 #### 一、EALREADY错误码的语义 当非阻塞套接字调用`connect()`时出现`errno=EALREADY`,表示**前一个连接请求仍在进行中**。这是TCP协议栈的状态保护机制,防止客户端重复发起无效连接请求[^1]。 **触发条件**: - 套接字已处于$SYN\_SENT$状态(已发送SYN包但未收到SYN+ACK) - 应用程序在未完成当前连接的情况下再次调用`connect()` **典型错误处理流程**: ```c int sockfd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0); connect(sockfd, ...); // 返回-1且errno=EINPROGRESS // 在未等待连接完成的情况下再次调用connect if (connect(sockfd, ...) == -1) { if (errno == EALREADY) { // 关键错误码判断 // 应停止重复调用,继续等待select/epoll事件 } } ``` #### 二、内核实现原理 1. **状态机检查** 内核在`__inet_stream_connect()`中检查套接字当前状态: ```c if (sk->sk_state == TCP_SYN_SENT || sk->sk_state == TCP_SYN_RECV) { sock->state = SS_CONNECTING; err = -EALREADY; // 触发错误码的根源[^1] goto out; } ``` 2. **连接队列管理** - 通过`reqsk_queue_remove()`管理半连接队列(SYN队列)[^3] - 每个套接字在$SYN\_SENT$状态时占用一个队列条目 - 重复连接请求会被直接拒绝以避免资源浪费 3. **事件通知机制** - 当三次握手完成时,内核调用`tcp_finish_connect()`: ```c tcp_set_state(sk, TCP_ESTABLISHED); // 更新状态[^4] sk->sk_state_change(sk); // 唤醒阻塞进程[^4] ``` - 通过`sock_def_wakeup()`唤醒等待队列中的进程 #### 三、编程建议与规避方法 | 场景 | 处理方法 | |---------------------|--------------------------------------------------------------------------| | 检测到EALREADY | 停止重复调用connect,继续等待select/epoll的写就绪事件 | | 连接超时处理 | 设置`TCP_USER_TIMEOUT`选项控制最大等待时间(默认约3分钟) | | 状态恢复 | 可调用`close()`后重新创建套接字 | | 异步事件监控 | 使用epoll的EPOLLOUT事件检测连接完成 | #### 四、典型错误处理代码 ```c int connect_nonblock(int sockfd, const struct sockaddr *addr, socklen_t addrlen) { int rc = connect(sockfd, addr, addrlen); if (rc == 0) return 0; if (errno != EINPROGRESS && errno != EALREADY) { // 处理非常规错误 return -1; } struct pollfd pfd = { .fd = sockfd, .events = POLLOUT }; while (1) { rc = poll(&pfd, 1, timeout_ms); if (rc > 0) { int error; socklen_t len = sizeof(error); getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &len); return (error == 0) ? 0 : -1; } // 处理超时和中断... } } ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值