尝试快速创建和销毁套接字以进行负载测试时出现“java.net.BindException:地址已在使用中”

问题描述 投票:0回答:4

我试图通过打开大量到服务器的套接字连接、身份验证、关闭连接,然后重复来对 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 个左右套接字。

任何帮助将不胜感激!

java sockets network-programming tcp
4个回答
24
投票

您在两分钟的 TIME_WAIT 时间内打开如此多的出站套接字会耗尽出站端口的空间。您应该问自己的第一个问题是,这是否代表了实际的负载测试?真正的客户真的会这样做吗?如果没有,您只需要修改您的测试方法即可。

BTW SO_LINGER 是 application 在 close() 期间等待数据刷新的秒数。通常为零。无论如何,如果这是发出关闭的一端,则端口将在 TIME_WAIT 间隔内挂起。这不是同一件事。可以滥用 SO_LINGER 选项来修补问题。然而,这也会导致同行出现异常行为,这也不是测试的目的。


1
投票

不使用bind()而是使用setReuseAddress(true)很奇怪,我希望你能理解setReuseAddress的含义(以及它的意义)。 100-2000 不是需要打开大量套接字,但是您尝试连接的服务器(因为它看起来相同的地址/端口对)可能会在正常积压的 50 个套接字中丢弃它们。

编辑: 如果您需要快速打开多个套接字(ermm 端口扫描?),我非常强烈建议使用 NIO 和 connect()/finishConnect() + 选择器。在同一个线程中打开 1000 个套接字实在是太慢了。 忘记了您的代码中可能需要 finishConnect() 。


0
投票

在 Java 客户端上运行压力测试时,我在 Mac OS 上看到相同的错误,该客户端打开了到单个 UDP 服务器端口的 100 多个并发 UDP 连接。

java.net.BindException:地址已在使用中

有解决办法吗?


-2
投票

我认为您应该计划要用于连接的端口正在使用中。 我的意思是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++
}

此代码不涵盖一些极端情况,例如“当所有端口都在使用时会发生什么?”

© www.soinside.com 2019 - 2024. All rights reserved.