网络编程中常见错误码总结

在网络编程中,总有各种需要注意的环节,几乎每个API都要进行异常处理,判断返回值以及错误码来定位是否需要退出.
本文根据自身使用经验,总结以下错误码及其出现场景和一般处理流程.
网络编程的一般性流程如下 :
客户端 : socket -> connect -> write / read
服务端 : socket -> bind -> listen -> accept
还有因为设置属性带来的其它改变,比如非阻塞和套接字选项.
EADDRINUSE : 如果你在同一个端口运行了无论是相同还是不同的程序,那么bind就会出错.即便是设置了SO_REUSEADDR,同一时刻也只允许同一个进程占用指定端口,有一种极其特殊的情况,就是允许相同地址端口的完全重复绑定,但是这个特殊的情况需要传输协议支持,而且一般而言仅适用于UDP.(参考unp 7.5.11)
EINTR : 如果你并未对套接字设置非阻塞,那么所有可能阻塞的函数都有可能遇到这个错误.比如connect,accept,read,write...等,面对这个错误,一般性的处理办法是忽略掉它,继续产生这个错误的操作.比如read一个套接字,如果遇到了这个错误,忽略掉,继续read就行了.
EINPROGRESS : 一次connect的超时时间可能是75s左右(参考unp 4.3),有的时候我们并不想等待这么长时间.有办法,可以在调用connect之前设置套接字非阻塞,然后调用connect,此时connect会立刻返回,并且会设置errno为EINPROCESS,这并不是一个致命错误,仅仅是告知你已经在连接了,你只要判断是它就继续执行后面的逻辑就行了,比如select.通过select设置超时来达到为connect设定超时的目的.
ECONNABORT : 一个连接到来了以后,accept并不会立刻返回,而是先把这个连接放在未完成连接队列,然后做一些处理以后放到已完成连接队列,accept所做的只是从已完成连接队列取这个连接而已,如果在accept取之前,连接异常断开,accept就会返回这个错误,当然这个错误并不致命,但是如果你这样写,你就惨了
if (errno == EINTR/* || errno == ECONNABORT*/)
{
    continue;
}
else
{
    return -1;
上面这段代码说明,当accept错误返回时,不仅要判断中断,还需要判断连接终止.
EAGAIN : 如果你得套接字是非阻塞的,你需要对read/write/recv/send...等函数判断返回值,如果其失败返回,并且errno是EAGAIN,这并不致命,你只要忽略它,继续处理就行,这个错误只是告诉我们,当前这个套接字并没有数据可读或者并没有空间装得下将要发送的数据.
EWOULDBLOCK : 在大多数的TCP实现中,这个错误码和EAGAIN的意思是一样的.参考百度百科
ESRCH : 这个错误码表示的是进程或者线程不存在,当你在处理复杂的多进程或者多线程环境的时候,可以围绕这个错误码做很多事情.
ECONNRESET : 当我们调用connect连接服务器的时候,若服务器返回的是RST,我们就会收到这样的错误.这看来算是一个致命的错误,如果遇到,要么一直连,要么就退出.
ETIMEDOUT : 如果你的套接字是阻塞的,你可能会在某个时间段内发不出数据,此时你就会收到ETIMEOUT
EHOSTUNREACH : 接上述场景,如果此时中间的某个路由器触发ICMP对端不可达错误,那么你的函数返回的错误码就会是这个.
EPERM : 这个错误码有点冷门了,我也是无意间遇到的.在编写广播程序的时候,如果采用了广播地址,却并未设置广播属性,就会出现这个errno
EPIPE 
: 这个错误应该是最复杂的一个错误了.我们首先需要了解的是在网络编程中的一个特殊场景.
当一个套接字已经关闭了以后,如果我们继续写这个套接字,你并不会察觉有什么异常,返回值告诉你,你写成功了,但是如果通过wireshark抓包,你会发现,接收端回复了一个RST,这个RST你根本就不知道.你唯一检测它的办法是读一下这个套接字,此时会返回0,你才发现,原来连接已经断开了.好吧,我假设我不管它,继续写,此时程序就会异常崩溃.是什么导致了程序的崩溃呢,就是SIGPIPE,这个信号的默认行为就是终止进程.
说回EPIPE,对于SIGPIPE,如果你没有捕获它,那么程序也就退出了,也就谈不上EPIPE了,所以,这个errno出现的前提一定是你设置了信号捕获.那么这个错误是否致命呢,看情况吧,反正连接也不在了,起码拿到错误以后应该close掉本端的套接字.
以上...

你可能感兴趣的:(c/c++)