我有一个打开套接字的测试应用程序,通过此套接字发送内容然后关闭它。这循环完成5-10.000次。问题是在3,4000次迭代后我得到了这种类型的错误:
java.net.BindException: Address already in use: connect
我甚至设置了即时使用的套接字,但错误仍然存在
try
{
out_server.write(m.ToByteArray());
socket_server.setReuseAddress(true);
socket_server.close();
}
catch(Exception e)
{
e.printStackTrace();
System.out.println(i+" unable to register with the server");
}
我该怎么做才能解决这个问题?
答案 0 :(得分:11)
我想你可能会走得太快。
大多数操作系统对任何时候都可以打开的插槽数量有限制,但实际上比这更糟糕。
当套接字关闭时,它将处于特定的时间等待状态一段时间。这通常是数据包生存时间值的两倍,它可以确保网络中没有仍然有数据包出现在您的套接字上。
一旦该时间到期,您可以确定网络中的所有数据包都已经死亡。套接字处于特殊状态,以便在关闭时将网络中的数据包丢弃,如果它们在死亡之前到达,则可以将其丢弃。
我认为这就是你的情况,插座并没有像你想象的那样快速释放。
我们遇到类似的问题,代码打开了很多短暂的会话。它运行良好一段时间,但随后硬件变得更快,允许在给定的时间段内打开更多。这表明自己无法开设更多会议。
检查这一点的一种方法是从命令行执行netstat -a
,看看有多少会话实际处于等待状态。
如果情况确实如此,那么有几种方法可以处理它。
最后一个要点值得一些扩展。我们实际上在前面提到的应用程序中使用了退避策略,如果它抱怨的话,它将逐渐减轻资源提供者的负担,而不是30秒的两秒延迟,我们选择了一秒钟的延迟,然后是两秒钟,然后四个等等。
退避策略的一般过程如下,它可用于可能暂时缺少资源的任何情况。下面的伪代码中提到的操作将是在您的情况下打开套接字。
set maxdelay to 16 # maximum time period between attempts
set maxtries to 10 # maximum attempts
set delay to 0
set tries to 0
while more actions needed:
if delay is not 0:
sleep delay
attempt action
if action failed:
add 1 to tries
if tries is greater than maxtries:
exit with permanent error
if delay is 0:
set delay to 1
else:
double delay
if delay is greater than maxdelay:
set delay to maxdelay
else:
set delay to 0
set tries to 0
这允许进程在绝大多数情况下以全速运行,但在错误开始时退出,希望给资源提供者时间恢复。延迟的逐渐增加允许更严格的资源限制来恢复,并且最大尝试会捕获您所谓的永久性错误(或者需要花费很长时间才能恢复的错误)。
答案 1 :(得分:2)
我的建议:
@Pax之后对套接字的状态有一个很好的观点。尝试使用您的代码,让它失败,然后执行netstat
并进行分析(或在此处发布)
答案 2 :(得分:2)
什么操作系统?如果你正在使用Windows,我猜你是,那么你可以拥有的客户端连接数量有限(这是由MaxUserPort
注册表项配置的,恰好是4000默认;有关更改的详细信息,请参阅http://technet.microsoft.com/en-us/library/aa995661.aspx和http://www.tech-archive.net/Archive/Windows/microsoft.public.windows.server.general/2008-09/msg00611.html。这与您从客户端关闭套接字并因此在客户端累积TIME_WAIT
状态的套接字这一事实可能是导致问题的原因。
请注意,TIME_WAIT
累积问题的解决方案不是摆弄TCP堆栈的参数以使问题消失。 TIME_WAIT
存在的原因非常充分,删除或缩短它可能会给您带来新的问题!
因此,假设您使用的是Windows计算机,第一步是调整MaxUserPort
值,以便为出站连接提供更多动态端口。接下来,如果这不能解决问题,您可以考虑连接的哪一端应该以{{1}}结束(假设您可以控制连接上使用的协议......)发布的对等方'主动关闭'是以TIME_WAIT
结尾的那个,所以如果你可以改变一些事情以便服务器发出主动关闭,那么TIME_WAIT
套接字将在服务器而不是客户端上累积这个 MAY 对你更好......
答案 3 :(得分:1)
我同意其他人说你的套接字端点用完了。但是,从您的示例中可能并非100%清晰,因为可能是异常来自connect()或bind()调用,该调用可能是其他一些高级Java方法的基础。
还应该强调的是,耗尽端点不是套接字库的某种限制,而是任何TCP / IP实现的基本部分。您需要保留有关旧连接的信息一段时间,以便丢弃旧连接的迟到IP数据包。
setReuseAddress()对应于低级SO_REUSEADDR套接字选项,仅在执行listen()时应用于服务器。
答案 4 :(得分:0)
我认为这与这个问题是一样的(我的答案与我的答案相关,我认为这可能有所帮助。)
答案 5 :(得分:0)
如果示例代码实际上是您执行循环的方式,则可能会出现错误的顺序。
setReuseAddress的java docs说:绑定套接字后启用或禁用SO_REUSEADDR时的行为(请参阅isBound())未定义。
尝试在调用bind()或connect()之前将调用移到某处。
答案 6 :(得分:0)
使用socket.close()之后的某个时候不会立即关闭套接字并且循环执行(在循环中它尝试套接字连接同样的ip和端口)要快得多,所以请将套接字置零。
socket_server.close();
socket_server = null;
由于 Sunil Kumar Sahoo