Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ruby-on-rails-3/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java HttpURLConnection:BindException在创建多个连接时发生异常_Java_Multithreading_Sockets_Http_Networking - Fatal编程技术网

Java HttpURLConnection:BindException在创建多个连接时发生异常

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秒的冷却时间后重新启动程序会导致相同的行为;当我不等待就立即重新启动它时,它会立即崩溃

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

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

    启动后,程序可以在短时间内正常运行,并且能够每秒执行约300个线程周期(Web服务器在同一台机器上运行)。但5-7秒后,我得到了
    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会帮您解决这些问题。