“java.net.BindException:地址已在使用中”尝试为负载测试进行快速套接字创建和销毁时
Posted
技术标签:
【中文标题】“java.net.BindException:地址已在使用中”尝试为负载测试进行快速套接字创建和销毁时【英文标题】:"java.net.BindException: Address already in use" when trying to do rapid Socket creation and destruction for load testing 【发布时间】:2011-06-10 04:01:58 【问题描述】:我正在尝试通过打开大量与服务器的套接字连接、身份验证、关闭连接然后重复来对 Java 服务器进行负载测试。我的应用运行了一段时间,但最终我得到:
java.net.BindException:地址已在使用中:连接
根据我阅读的文档,原因是关闭的套接字在调用 close() 后仍然占用分配给它们的本地地址一段时间。这取决于操作系统,但可能需要几分钟。我尝试在套接字上调用setReuseAddress(true)
,希望在调用close()
后它的地址可以立即重用。不幸的是,情况似乎并非如此。
我的套接字创建代码是:
Socket socket = new Socket();
socket.setReuseAddress(true);
socket.connect(new InetSocketAddress(m_host, m_port));
但我仍然收到此错误:
java.net.BindException:地址已在使用中:稍后连接。
还有其他方法可以完成我想做的事情吗?例如,我想:打开 100 个套接字,全部关闭,打开 200 个套接字,全部关闭,打开 300 个等等。最多 2000 个左右的套接字。
任何帮助将不胜感激!
【问题讨论】:
是服务器还是客户端抛出了异常?连接数一致后是否会发生这种情况? 您可能需要更改机器的 TCP 设置,请参阅docs.alfresco.com/4.0/topic/com.alfresco.enterprise.doc/tasks/… 【参考方案1】:您在两分钟的 TIME_WAIT 时间段内打开了这么多出站套接字,从而耗尽了出站端口的空间。您应该问自己的第一个问题是,这是否代表了实际的负载测试?真正的客户真的会这样做吗?如果没有,您只需修改测试方法即可。
BTW SO_LINGER 是 应用程序 在 close() 期间等待数据刷新的秒数。它通常为零。如果这是发出关闭的结束,则端口无论如何都会在 TIME_WAIT 间隔内徘徊。这不是一回事。可能会滥用 SO_LINGER 选项来修补问题。但是,这也会导致对等方出现异常行为,这也不是测试的目的。
【讨论】:
你是对的,没有真正的客户端会打开那么多连接。在我的应用程序中,真正的客户端只会打开 1 个与服务器的 TCP 连接。我想做的是模拟真实的客户端,我希望尽可能多的模拟客户端在同一台机器上运行。 您的回复也帮助了我! :-) 我想在这里补充一点,如果您使用 setSoLinger() 方法,它会导致已经连接的对等点出现问题,并且它们有时也会断开连接!真的不知道是什么导致了这种行为,但我花了 45 分钟才弄清楚! @M2X SO_LINGER off 是默认设置,这会导致close()
表现得像我们现在所爱的那样。如果您将其设置为“开启”并且超时时间为零,它会导致close()
和shutdown()
发出重置而不是正确关闭。我什至不想提及这一点,因为这是一种不受欢迎的行为。如果有任何正当理由在一个普通的 TCP/IP 应用程序中弄乱 SO_LINGER,我还没有遇到过它们......在近三十年里。
@rogerdpack '重新分配套接字' 毫无意义。没有这样的操作。我不知道你在这里问什么。【参考方案2】:
不使用 bind() 但 setReuseAddress(true) 很奇怪,我希望你明白 setReuseAddress 的含义(以及它的意义)。 100-2000 不是要打开大量套接字,但是您尝试连接的服务器(因为它看起来是相同的地址/端口对),可能只是将它们与正常的积压一起丢弃50 个。
编辑: 如果您需要快速打开多个套接字(ermm 端口扫描?),我非常强烈建议使用 NIO 和 connect()/finishConnect() + Selector。在同一个线程中打开 1000 个套接字非常慢。 忘了你的代码中可能需要finishConnect()。
【讨论】:
【参考方案3】:我认为您应该计划好要用来连接的端口是否处于使用状态。我的意思是 try 使用给定的端口进行连接。如果连接失败(或者在您的情况下引发异常),请尝试使用下一个端口号打开连接。
尝试将connect
语句包装在try/catch
中。
下面是一些伪代码,表达了我认为可行的内容:
portNumber = x //where x is the first port number you will try
numConnections = 200 // or however many connections you want to open
while(numConnections > 0)
try
connect(host, portNumber)
numConnections--
catch()
portNumber++
此代码不涵盖诸如“所有端口都在使用时会发生什么?”之类的极端情况。
【讨论】:
这没有任何意义。他正在尝试连接到一个正在侦听固定端口号的服务,而不是一个可以递增的服务,他的问题是本地端口空间,而不是远程端口空间。 如果您真的很绝望,这样的事情可能会有所帮助:该端口仍在使用中有问题吗?再试一次! :) @rogerdpack 只有在你不知道目标端口并且你不知道你什么都不知道的情况下才会有所帮助。这里提供的代码是一个端口扫描器,在任何意义上都不是传统的 TCP 客户端。这个答案与所提出的问题无关。以上是关于“java.net.BindException:地址已在使用中”尝试为负载测试进行快速套接字创建和销毁时的主要内容,如果未能解决你的问题,请参考以下文章