当前位置: 首页 > Linux

TCP-socket异常情况

时间:2023-04-06 11:34:53 Linux

在Unix下进行网络编程时,由于网络不完全可靠,各种协议的主进程外会出现各种错误。一个健壮的程序必须考虑到这些错误并正确处理它们,因此这里总结了网络编程中可能出现的常见错误。TCP异常处理整体响应超时在握手、挥手、消息传递状态下,当前发送的消息是否期望响应消息。如果响应消息在指定时间内没有到达,发送方将重新发送消息两次(消息重发间隔可以设置)。如果3次重传仍未收到响应,则将ETIMEOUTdestinationunreachable返回给应用程序。上述方法重发二次消息。如果重传结束后仍未收到响应,则返回EHOSTUNREACH或ENETUNREACH给应用禁止分片在IPV4中,超过MTU长度的数据包会导致分片,有DF(Don'tFragment)标志,表示禁止分片。同时IPV6禁止路由器分片,因此在传输过程中隐含了DF位。如果在传输过程中设置了DF位,超过了MTU,EMSGSIZE会返回给应用程序,阻塞时中断Blocked当系统执行慢系统调用(可能永远阻塞的系统调用)时,捕获一个信号并executed如果不处理(系统对某些信号有默认的处理方式),如果没有设置自动重启,会返回EINTR给应用程序。一般处理EINTR的方式就是简单的再次调用,但是这样不行当connect返回EINTR时才完成,因为connect涉及三次握手过程,需要使用getsockopt获取连接状态。读写时,RST在调用read等阻塞时收到对端的RST信号后会返回ECONNREST。同时,在向发送方断开连接的套接字写入时,也会返回ECONNRESET写入RST套接字当进程对接收到RST的套接字进行写操作时,内核向进程发送SIGPIPE信号,默认行为是终止进程,因此进程必须捕获它以避免被不情愿地终止无论进程捕获信号并从信号处理程序返回,还是干脆忽略信号,写操作都会返回EPIPE错误握手partofthefirsthandshakeServerRST客户端第一次握手时,如果服务器返回RST报文,则立即返回ECONNREFUSED给应用程序,结束握手。对于随机发送RST包的情况,posix指出,在这种情况下,errno设置为ECONNABORTED,只需要再次调用accept即可。在Berkeley的实现中,会返回一个EPROTO错误,代表协议错误,这是一个致命错误。内核从已完成的连接套接字队列中释放连接。如果再调用accept,直到本次request才会处理,可能造成阻塞。服务器主机部分数据传输部分当机。由于客户端无法收到服务器的任何响应,它将重新发送处理。应用程序最终返回可能是响应超时或者目的地不可达。如果想尽快检测到主机的崩溃,可以不主动发送数据,也就是socket选项的SO_KEEPALIVE(类似心跳机制)挥动一些服务器进程终止或关闭。服务器崩溃或被手动终止后,进程终止将关闭所有打开的描述符。这导致它向客户端发送了一个FIN,客户端回应了一个ack,前半段TCPwave完成,服务器不再发送数据。但是此时客户端并不知道服务器已经终止。当客户端向服务器写入数据时,由于服务器进程终止,它响应RST。在这种情况下,可以通过select或poll检测到服务器的终止。如果对端TCP发送数据,则socket可读,read返回大于0的值(读取的字节数)如果对端TCP发送FIN(对端进程终止),则socket可读,read返回0(EOF)如果对端TCP发送RST(对端崩溃重启),则socket可读,read返回-1,errno包含准确的错误码。服务器终止并重启,因为重启后socket已经丢失了socket连接信息,服务器用RST响应客户端的消息。如果客户端此时读取,会返回ECONNRESETsocketapiexceptionsocketerrno意思可能是致命的解决方法EACCES权限不足√EAFNOSUPPORT地址族不支持参数错误√EINVAL参数错误未知协议或协议族不可用√EMFILE打开文件太多manyprocess-levelopenedfdsreachedupperlimitulimit-nadjustorwaitforresourcereleaseENFILEtoomanyopenfilesopensystem-levelopenfdsreachingtheupperlimitandwaitingresourcereleaseENOBUFS/ENOMEMInsufficientmemoryBufferorfiletable不能createdWaitingforresourcereleasebinderrno意思可能是致命的情况。解决EACCES权限不足申请保留端口无root运行问题。√EADDRINUSE地址已被使用。绑定使用过的地址或者申请一个临时端口。当临时端口已满时重试。EBADFfdisnotavailablefdisclosedortheparametererrorsocketrepeatedbindingorparametererror√ENOTSOCKnon-socketfd参数错误√listenerrno含义可能是致命的解决临时端口满时重试EBADFfdisunavailablefdisclosedortheparameterisillegal√ENOTSOCKnon-socketfdparametererror√EOPNOTSUPPoperationdoesnotsupportonlySOCK_STREAMtypesocket(TCP)√accepterrno含义可能是致命的解决EWOULDBLOCK/EAGAIN资源暂时不可用(非阻塞)没有队列中的握手连接重试或处理其他事务addr参数没有指向用户可写空间√EINTR调用中断调用被信号中断重试或处理其他事务上限ulimit-n调整或等待资源释放ENFILEToomanyopenfilesSystem-levelopenfdreachedtheupperlimitWaitingforresourcereleaseENOMEM/ENOBUFSInsufficientmemorySocketbuffer内存不足而非系统内存不足等待??资源释放Connecterrno含义可能情况FatalsolutionInsufficientEACCES/EPERMauthority/operationnotallowed没有设置广播标志但连接被广播地址或防火墙禁止√EADDRINUSE本地地址已被使用,重试,等待资源释放EADDRNOTAVAIL地址不可用,未绑定某个端口,临时端口已被占用重试,等待资源释放EAFNOSUPPORT地址族错误√EAGAIN资源暂时不可用否localportavailableorTherenorecordintheroutingcache(?)重试,等待资源释放EALREADYconnectionisbeingprocessed(non-blocking)之前的连接还没有处理完,可能是重新调用返回EINPROGRESS√EBADFfdisnotavailablefdisclosedortheparameterisillegal√ECONNREFUSEDconnectionRejectthegivenremoteendnotlistening,orseethefirsthandshakeserverRSTretryEFAULTaddresserror地址指针超出用户空间√EINPROGRESS操作进行中(非阻塞)connect无法立即完成使用getsockopt判断连接是错误还是完成EINTRcallinterrupt调用被信号中断。使用getsockopt确定连接是错误还是已完成。EISCONN套接字已连接。使用getsockopt确定连接是错误还是已完成。字协议错误√ETIMEDOUT连接超时,对端无响应。可能是因为系统忙,重试...EINTR/EINPROGRESS/EALREADY代表的情况如果connect()被阻塞等待建立连接时捕获到的信号中断,connect()应该失败,设置connect()到[EINTR],但连接请求不应中止,连接应异步建立。如果不能立即建立连接,并且为文件描述符fo设置了O_NONBLOCKr套接字,connect()应失败并将errno设置为[EINPROGRESS],但不应中止连接请求,并且应异步建立连接。在建立连接之前,对同一个套接字的后续调用connect()将失败并将errno设置为[EALREADY]。当异步建立连接时,select()和poll()将指示用于该套接字的文件描述符socketisreadyforwriting.read(onlysocketinvolved)errnomeaningPossiblefatalsolutionEAGAIN/EWOULDBLOCKoperationwillblock(non-blocking)BufferemptyretryEBADFfdisunavailablefdisclosedorparameterisillegal不可读√write(socketonly)errno含义可能致命解决EAGAIN/EWOULDBLOCK操作会阻塞(非阻塞)BufferisfullorinsufficientfreespacetoretryEBADFfdisnotavailablefdisclosedortheparameterisillegaltheaddresssocketisnotconnected√EFAULTaddresserrorbufferexceeds用户空间√EINTR调用中断调用被信号中断重试EINVAL参数错误√EPIPE管道错误writetoreadclose结束,见writeRSTsocket√