端口占用错误
这两天在工作的过程中发现基于socket的网络程序中时不时发生connect()调用失败的错误,通过获取错误码,发现是WSAEADDRINUSE(10048)的错误,MSDN的说明如下:
这种错误常常发生在bind函数中,当bind已经绑定的端口被占用后,再次绑定同一端口就会发生错误,但这一错误不影响bind的执行,换句话说,bind第二次执行并不发生错误,但是在紧接着调用connect()时会出错,错误码就是10048。
应用程序调用bind在使用随机端口绑定时,如果操作系统预留的1024~5000之间的端口都被占用着的话,bind不出错,connect会失败。
什么情况下端口会被全部占用?
情况一:如果每个端口上都正在进行数据操作,那么端口就都处于占用状态。
情况二:connect的频率太快,每一个socket在调用closesocket进行关闭操作后,虽然closesocket执行完毕,但是对应的占用端口并不是立即释放,这些端口需要继续处于占用状态,等待时间大约2ML(数据包最大生存周期),默认最大值为4分钟。用netstat命令查看端口状态,端口显示TIME_WAIT,在4分钟内如果对同一个端口进行connect,就会发生10048错误。
如何修正错误?
方法一: 如果使用了bind函数,那么可以对绑定的端口进行指定,如果调用connect失败,那么就返回bind处更改绑定端口,然后继续connect,直到成功为止。
方法二: 如果没有使用bind函数,直接使用connect进行连接,那么可以对connect操作进行retry,在这种情况下如果connect失败,那么它下次被调用时仍会使用调用失败的端口进行连接,直到连接成功。
retry的间隔时间和次数如何确定?
理想的设定是retry的间隔时间要尽量短,次数要尽量少,但这两者是相互矛盾的,往往retry的总时间是一定的,也就是说retry的时间间隔短了,次数就多了;retry的时间间隔长了,次数就少了。呵呵,这里感觉很不好选择,那么只有通过实际的程序测试来判断了。