HttpURLConnection:创建多个连接时发生BindException

为了测试/基准测试的目的,我想编写一个Java程序,在循环中执行以下任务:

  • 通过HTTP GET从服务器加载数据
  • (根据收到的数据生成一个答案 - 在这一点上不重要)
  • 通过HTTP POST将答案发送到同一台服务器
  • 此循环同时在多个线程上运行。

    启动后,程序在短时间内运行良好,并且能够每秒执行约300个循环(网络服务器在同一台机器上运行)。 但5-7秒后,我得到BindException: Address already in use

    在20-30秒冷却时间后重新启动程序会导致相同的行为; 当我立即重新启动而不等待时,它立即崩溃......所以我想这可能是一个绑定资源的问题。

    这是一个使用HttpURLConnection的快速和肮脏的方法。 相关部分:

    从网络服务器获取数据

    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)
    

    它出现在下面一行的fetchdata方法中:

    in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
    

    我删除了disconnect()的调用(正如Aaron指出的那样) - 不幸的是,同样的问题依然存在。


    让我们假设一切都正确关闭(不知道这是否是这种情况,只要让我们假设它) - 情况可能是程序太快了吗? 我在stackoverflow上发现了另一篇文章,“解决方案”是添加一个简单的Thread.sleep - 但由于它是一个基准,并且应该尽可能快地运行,所以我不喜欢这样。 负载测试工具如何处理这个问题?


    我将线程数量减少到1,即使出现问题。


    这听起来像你可能会用完本地端口。 是否有可能并行产生太多连接,并且没有足够快地释放其资源以便其他线程重用?

    我会摆脱disconnect()的调用,因为这几乎会禁用连接池。 从文档:

    表示在不久的将来,对服务器的其他请求不太可能。 调用disconnect()不应该暗示此HttpURLConnection实例可以重用于其他请求。


    我想你已经没有本地端口来检查这个了:运行你的程序并运行netstat命令。 尝试使用HttpClient使用连接池进行http连接HTTP连接池


    看起来你正在用尽本地端口。 为了防止这种情况,你必须确保你的连接被重用。 Java会尽力为你做,但你需要为每个请求读取整个响应。

    虽然fetchData函数读取响应,但sendData不会。 虽然在这里你不需要响应体,但你仍然应该阅读它(直到最后),然后关闭相应的InputStream 。 那么这个连接可能会被重用。

    也不要disconnect你的连接。

    这个问题可能会有所帮助。

    链接地址: http://www.djcxy.com/p/22949.html

    上一篇: HttpURLConnection: BindException when creating many connections

    下一篇: How to define a function on a struct pointer in assembly?