套接字绑定错误

我有一个测试应用程序打开一个套接字,通过这个套接字发送一些东西,然后关闭它。 这循环完成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"); } 

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

我想你可能会走得太快。

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

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

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

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

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

检查这一点的一种方法是从命令行执行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 

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

我的建议:

  • 写入后刷新套接字
  • 在上述方法结束时添加一个小睡眠(~50ms?)

之后@Pax对套接字的状态有一个很好的观点。 尝试你的代码,让它失败,然后做一个netstat并分析它(或发布在这里)

什么操作系统? 如果您正在使用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值,以便为出站连接提供更多动态端口。 接下来,如果这不能解决问题,您可以考虑连接的哪一端应该以TIME_WAIT结束(假设您可以控制连接上使用的协议……)发出’主动关闭的对等方’是以TIME_WAIT结束的那个,所以如果你可以更改东西以便你的服务器发出主动关闭,那么TIME_WAIT套接字将在服务器而不是客户端上积累,这对你来说可能更好……

我同意其他人说你的套接字端点用完了。 但是,从您的示例中可能并非100%清晰,因为可能是exception来自connect()或bind()调用,该调用可能是其他一些高级Java方法的基础。

还应该强调的是,耗尽端点不是套接字库的某种限制,而是任何TCP / IP实现的基本部分。 您需要保留有关旧连接的信息一段时间,以便丢弃旧连接的迟到IP数据包。

setReuseAddress()对应于低级SO_REUSEADDR套接字选项,仅在执行listen()时应用于服务器。

我认为这与这个问题是一样的(我和我的答案有关,我认为这可能会有所帮助。)

Java绑定exception

如果示例代码实际上是您执行循环的方式,那么您可能会以错误的顺序执行操作。

setReuseAddress的java文档说:绑定套接字后启用或禁用SO_REUSEADDR时的行为(请参阅isBound())未定义。

尝试在bind()或connect()之前将调用移动到某个位置。

使用socket.close()之后的某个时候不会立即关闭套接字并且循环执行(在循环中它尝试与同一个ip和端口的套接字连接)要快得多,所以请将套接字置零。

socket_server.close();

socket_server = null;

谢谢Sunil Kumar Sahoo