套接字绑定错误

kla*_*han 4 java sockets

我有一个测试应用程序打开一个套接字,通过这个套接字发送一些东西然后关闭它.这循环完成5-10.000次.事情是,在3,4000次迭代后,我得到了这种类型的错误:

java.net.BindException: Address already in use: connect
Run Code Online (Sandbox Code Playgroud)

我甚至设置了即时使用的套接字,但错误仍然存​​在

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");
}
Run Code Online (Sandbox Code Playgroud)

我该怎么做才能解决这个问题?

pax*_*blo 11

我想你可能走得太快了.

大多数操作系统都限制了它们在任何时候都可以打开的插槽数量,但它实际上比这更糟糕.

当套接字关闭时,它将处于特定的时间等待状态一段时间.这通常是数据包生存时间值的两倍,它可以确保网络中没有仍然存在的数据包正在通往套接字的路上.

一旦该时间到期,您可以确保网络中的所有数据包都已经死亡.套接字处于特殊状态,以便在关闭时将网络中的数据包丢弃,如果它们在死亡之前到达,则可以将其丢弃.

我认为这就是你的情况,插座并没有像你想象的那样快速释放.

我们遇到了类似的问题,代码打开了很多短暂的会话.它运行良好一段时间,但随后硬件变得更快,允许在给定的时间段内打开更多.这表明自己无法开设更多会议.

检查此问题的一种方法是netstat -a从命令行执行操作,查看实际处于等待状态的会话数.

如果情况确实如此,那么有几种方法可以处理它.

  • 手动或通过维护连接池重用会话.
  • 在每个连接中引入延迟以尝试并停止到达饱和点.
  • 直到你达到饱和状态然后修改你的行为,例如在while语句中运行你的连接逻辑,每次重试最多60次,每次延迟两秒,然后完全放弃.这使您可以全速运行,只有在出现问题时才会减速.

最后一个要点值得一些扩展.我们实际上在前面提到的应用程序中使用了退避策略,如果它抱怨的话,它将逐渐减轻资源提供者的负担,而不是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
Run Code Online (Sandbox Code Playgroud)

这允许进程在绝大多数情况下以全速运行,但在错误开始时退出,希望为资源提供者提供恢复时间.延迟的逐渐增加允许更严格的资源限制来恢复,并且最大的尝试捕获您所谓的永久性错误(或者需要花费太长时间才能恢复的错误).

  • 摆弄这些参数并不总是一个好主意.大多数应该针对网络特性进行调整,然后应该调整应用程序.在不缩短生存时间的情况下减少time_wait将导致伪数据包到达.将TTL降低到数据包无法到达目的地的位置意味着丢弃大量数据包.理想情况下,您应该保持连接打开(手动或使用连接池)或调整应用程序行为(例如@Stu在他的回答中提到的延迟). (2认同)