Java HttpURLConnection:BindException在创建多个连接时发生异常
出于测试/基准测试的目的,我想编写一个Java程序,在循环中执行以下任务:Java HttpURLConnection:BindException在创建多个连接时发生异常,java,multithreading,sockets,http,networking,Java,Multithreading,Sockets,Http,Networking,出于测试/基准测试的目的,我想编写一个Java程序,在循环中执行以下任务: 通过HTTP GET从服务器加载数据 (根据接收到的数据生成答案-此时不重要) 通过HTTP POST将答案发送到同一服务器 此周期同时在多个线程上运行 启动后,程序可以在短时间内正常运行,并且能够每秒执行约300个线程周期(Web服务器在同一台机器上运行)。但5-7秒后,我得到了BindException:地址已在使用中 在20-30秒的冷却时间后重新启动程序会导致相同的行为;当我不等待就立即重新启动它时,它会立即崩溃
BindException:地址已在使用中
在20-30秒的冷却时间后重新启动程序会导致相同的行为;当我不等待就立即重新启动它时,它会立即崩溃。。。所以我想这可能是绑定资源的问题
使用HttpURLConnection
是一种快速而肮脏的方法。有关部分:
从Web服务器获取数据
public String fetchData() throws IOException {
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
conn.setUseCaches(false);
conn.setRequestMethod("GET");
BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
conn.disconnect();
return response.toString();
}
public void sendData(byte[] data) throws IOException {
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
conn.setUseCaches(false);
conn.setRequestMethod("POST");
conn.setDoOutput(true);
OutputStream os = conn.getOutputStream();
os.write(data);
os.close();
conn.disconnect();
}
发送答案
public String fetchData() throws IOException {
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
conn.setUseCaches(false);
conn.setRequestMethod("GET");
BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
conn.disconnect();
return response.toString();
}
public void sendData(byte[] data) throws IOException {
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
conn.setUseCaches(false);
conn.setRequestMethod("POST");
conn.setDoOutput(true);
OutputStream os = conn.getOutputStream();
os.write(data);
os.close();
conn.disconnect();
}
在线程内调用这两个方法
@Override
public void run() {
while(true) {
try {
String data = fetchData();
String answer = // ... generating answer
sendData(answer.getBytes("UTF-8"));
} catch (IOException e) {
// ...
}
}
}
没有一个URL对象在线程之间共享-每个线程都有自己的URL实例(但是,每个实例指向相同的地址)
编辑:
下面是发生的第一个异常的堆栈跟踪:
java.net.BindException: Address already in use: connect
at java.net.DualStackPlainSocketImpl.connect0(Native Method)
at java.net.DualStackPlainSocketImpl.socketConnect(Unknown Source)
at java.net.AbstractPlainSocketImpl.doConnect(Unknown Source)
at java.net.AbstractPlainSocketImpl.connectToAddress(Unknown Source)
at java.net.AbstractPlainSocketImpl.connect(Unknown Source)
at java.net.PlainSocketImpl.connect(Unknown Source)
at java.net.SocksSocketImpl.connect(Unknown Source)
at java.net.Socket.connect(Unknown Source)
at java.net.Socket.connect(Unknown Source)
at sun.net.NetworkClient.doConnect(Unknown Source)
at sun.net.www.http.HttpClient.openServer(Unknown Source)
at sun.net.www.http.HttpClient.openServer(Unknown Source)
at sun.net.www.http.HttpClient.<init>(Unknown Source)
at sun.net.www.http.HttpClient.New(Unknown Source)
at sun.net.www.http.HttpClient.New(Unknown Source)
at sun.net.www.protocol.http.HttpURLConnection.getNewHttpClient(Unknown Source)
at sun.net.www.protocol.http.HttpURLConnection.plainConnect0(Unknown Source)
at sun.net.www.protocol.http.HttpURLConnection.plainConnect(Unknown Source)
at sun.net.www.protocol.http.HttpURLConnection.connect(Unknown Source)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(Unknown Source)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(Unknown Source)
at PayloadProcessor.fetchData(PayloadProcessor.java:66)
at PayloadProcessor.run(PayloadProcessor.java:32)
at java.lang.Thread.run(Unknown Source)
我删除了对
disconnect()
(正如Aaron所指出的)的调用-不幸的是,同样的问题仍然存在
让我们假设所有的东西都正确地关闭了(不确定这里是否是这种情况,让我们假设一下)-是不是程序太快了?我在stackoverflow上发现了另一个“解决方案”是添加一个简单的Thread.sleep,但是因为它是一个基准测试,应该尽可能快地运行,所以我不喜欢这样。负载测试工具如何处理这个问题
我将线程数量减少到1,即使出现了问题。听起来您的本地端口可能已经用完了。是否有可能并行生成了太多的连接,并且没有足够快地释放它们的资源以供其他线程重用 我将取消对
disconnect()
的调用,因为这将基本上禁用连接池。从文档中:
表示在不久的将来不太可能向服务器发出其他请求。调用disconnect()不应意味着此HttpURLConnection实例可用于其他请求
我认为您的本地端口已用完,无法检查: 运行程序并运行netstat命令。 尝试对http连接使用连接池
看起来您的本地端口快用完了。为了防止这种情况,您必须确保重新使用连接。Java将尝试这样做,但您需要读取每个请求的整个响应 当
fetchData
函数读取响应时,sendData
不读取响应。虽然这里不需要响应正文,但您还是应该阅读它(直到最后),然后关闭相应的InputStream
。然后可以重用此连接
也不要断开连接
可能会有帮助。要获取和发送数据,您需要为每个
fetchData
和sendData
调用创建一个HttpURLConnection
。这意味着,您与服务器的连接太多。如前所述,这将使所有可用的本地端口号都用完
只需为每个线程创建一个HttpURLConnection
。我强烈建议您重构给定代码,如下所示:
@Override
public void run() {
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
while(true) {
try {
String data = fetchData(conn);
String answer = // ... generating answer
sendData(conn, answer.getBytes("UTF-8"));
} catch (IOException e) {
// ...
}
}
}
也就是说,在while循环之外创建一次
HttpURLConnection
对象,并将其作为参数传递给fetchData
和sendData
简单的解决方法就是在回答之前引入延迟
String data = fetchData(conn);
String answer = // ... generating answer
Thread.sleep(1000);
sendData(conn, answer.getBytes("UTF-8"));
在这里发布错误的完整堆栈跟踪可能很有用。无论如何,我建议您做的第一件事是将断开连接调用包含在finally子句中:可能出现了太多异常,导致连接没有正确关闭,从而导致泄漏。谢谢,我添加了堆栈跟踪。您是对的,确实存在许多异常-但是出于调试目的,我现在在第一个异常出现后终止程序(上面的代码中没有显示),并且仍然存在相同的问题。第一个异常已经是BindException。请在操作系统中添加命令
netstat-anpt | grep
或其类似命令的结果。您与一台服务器有多个连接。Web服务器(或servlet容器)对连接有限制。你用什么服务器?谢谢。我删除了对disconnect()
的两个调用,但不幸的是,它没有改变任何东西。我同意你关于缺少端口的观点,但我不知道为什么会发生这种情况。是程序太快了吗?看看我的编辑嗯…肯定是出了什么问题。您能告诉我们您的catch块中有什么吗?我还建议使用HttpClient而不是直接HttpURLConnection。直接使用HttpURLConnection可能会出现各种可怕的问题,HttpClient会帮您解决这些问题。