“java.net.BindException:地址已在使用中”当尝试快速创建和销毁套接字以进行负载测试时
我试图通过打开大量到服务器的套接字连接、验证、关闭连接,然后重复来对 Java 服务器进行负载测试。我的应用程序运行良好一段时间,但最终我得到:
java.net.BindException: Address already in use: connect
根据我阅读的文档,其原因是关闭的套接字在调用 close() 后的一段时间内仍然占用分配给它们的本地地址。这取决于操作系统,但可能需要几分钟的时间。我尝试在套接字上调用 setReuseAddress(true)
,希望在调用 close()
后其地址可以立即重用。不幸的是,情况似乎并非如此。
我的套接字创建代码是:
Socket socket = new Socket();
socket.setReuseAddress(true);
socket.connect(new InetSocketAddress(m_host, m_port));
但我仍然收到此错误:
java.net.BindException: Address already in use: connect after awhile.
还有其他方法可以完成我想要做的事情吗?例如,我想:打开 100 个套接字,全部关闭,打开 200 个套接字,全部关闭,打开 300 个,等等,最多 2000 个左右的套接字。
I'm trying to load test a Java server by opening a large number of socket connections to the server, authenticating, closing the connection, then repeating. My app runs great for awhile but eventually I get:
java.net.BindException: Address already in use: connect
According to documentation I read, the reason for this is that closed sockets still occupy the local address assigned to them for a period of time after close() was called. This is OS dependent but can be on the order of minutes. I tried calling setReuseAddress(true)
on the socket with the hopes that its address would be reusable immediately after close()
was called. Unfortunately this doesn't seem to be the case.
My code for socket creation is:
Socket socket = new Socket();
socket.setReuseAddress(true);
socket.connect(new InetSocketAddress(m_host, m_port));
But I still get this error:
java.net.BindException: Address already in use: connect after awhile.
Is there any other way to accomplish what I'm trying to do? I would like to for instance: open 100 sockets, close them all, open 200 sockets, close them all, open 300, etc. up to a max of 2000 or so sockets.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
通过在两分钟的 TIME_WAIT 时间内打开如此多的出站套接字,您将耗尽出站端口的空间。您应该问自己的第一个问题是,这是否代表了实际的负载测试?真正的客户真的会这样做吗?如果没有,您只需要修改您的测试方法。
BTW SO_LINGER 是应用程序在 close() 期间等待数据刷新的秒数。通常为零。无论如何,如果这是发出关闭的一端,则端口将在 TIME_WAIT 间隔内挂起。这不是同一件事。可以滥用 SO_LINGER 选项来修补问题。然而,这也会导致同行出现异常行为,这也不是测试的目的。
You are exhausing the space of outbound ports by opening that many outbound sockets within the TIME_WAIT period of two minutes. The first question you should ask yourself is does this represent a realistic load test at all? Is a real client really going to do that? If not, you just need to revise your testing methodology.
BTW SO_LINGER is the number of seconds the application will wait during close() for data to be flushed. It is normally zero. The port will hang around for the TIME_WAIT interval anyway if this is the end that issued the close. This is not the same thing. It is possible to abuse the SO_LINGER option to patch the problem. However that will also cause exceptional behaviour at the peer and again this is not the purpose of a test.
不使用 bind() 而是 setReuseAddress(true) 很奇怪,我希望您确实理解 setReuseAddress 的含义(及其要点)。 100-2000 并不是要打开的大量套接字,但是您尝试连接的服务器(因为它看起来相同的地址/端口对)可能会在正常的积压中删除它们共 50 条。
编辑:
如果您需要快速打开多个套接字(ermm 端口扫描?),我非常强烈建议使用 NIO 和 connect()/finishConnect() + 选择器。在同一个线程中打开 1000 个套接字实在是太慢了。
忘记了您的代码中可能需要 finishConnect() 。
Not using bind() but setReuseAddress(true) is just weird, I hope you do understand the implications of setReuseAddress (and the point of). 100-2000 is not a great number of sockets to open, however the server you are attempting to connect to (since it looks the same addr/port pair), may just drop them w/ a normal backlog of 50.
Edit:
if you need to open multiple sockets quickly (ermm port scan?), I'd very strongly recommend using NIO and connect()/finishConnect() + Selector. Opening 1000 sockets in the same thread is just plain slow.
Forgot you may need finishConnect() either way in your code.
我认为您应该计划要用于连接的端口。我的意思是尝试使用给定的端口进行连接。如果连接失败(或者在您的情况下引发异常),请尝试使用下一个端口号打开连接。
尝试将
connect
语句包装在try/catch
中。下面是一些伪代码,传达了我认为可行的内容:
此代码不涵盖诸如“当所有端口都在使用时会发生什么?”之类的极端情况。
I think that you should plan on the port you want to use to connect to be in use. By that I mean try to connect using the given port. If the connect fails (or in your case throws an exception), try to open the connection using the next port number.
Try wrapping the
connect
statement in atry/catch
.Here's some pseudo-code that conveys what I think will work:
This code doesn't cover corner cases such as "what happens when all ports are in use?"