6

我写了一小段java程序如下:

package com.ny.utils.pub;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

public class NetWriter {
private static String link = "http://xxx.yyyyyy.com:4444";

public String getLink() {
    return link;
}

public static void setLink(String link) {
    NetWriter.link = link;
}

private static HttpURLConnection conn = null;
private static BufferedReader bufReader = null;
private static InputStreamReader isReader = null;
private static OutputStreamWriter osw = null;
private static URL url = null;
static {
    try {
        url = new URL(link);
    } catch(MalformedURLException e) {
    }
}

public static void write(String msg) {
    long threadId = Thread.currentThread().getId();
    System.out.println("--Insert>{" + threadId + "}:" + msg);
    try {
        conn = (HttpURLConnection) url.openConnection();
        conn.setRequestMethod("POST");
        conn.setRequestProperty("Content-Type", 
              "application/x-www-form-urlencoded");
        conn.setRequestProperty("Content-Language", "en-US");
        conn.setUseCaches(false);
        conn.setDoOutput(true);
        conn.setReadTimeout(5000);
        conn.setConnectTimeout(5000);

        osw = new OutputStreamWriter(conn.getOutputStream());
        osw.write(msg);
        osw.flush();
        osw.close();

        if (conn.getResponseCode() != HttpURLConnection.HTTP_OK) {
            System.err.println("Server not return HTTP_OK status");
        } else {
            System.out.println(" request: " + msg);
            isReader = new InputStreamReader(conn.getInputStream());
            bufReader = new BufferedReader(isReader);
            String rep = bufReader.readLine();
            if (conn.getResponseCode() == 200) {
                System.out.println("Post data OK to " + link);
            }
            System.out.println(" response: " + rep);
        }
    } catch(IOException e) {
        System.err.println("Post data error: " + link + " "
                + e.getMessage());
        e.printStackTrace();
    }
}
}

当我编写另一个程序调用该类中的方法时,这将导致“打开的文件过多”,然后操作系统将拒绝用户登录。调用脚本如下:

try{        
    NetWriter.write(new String(content, "utf-8")); 
}catch(Exception e){
    logger.error(e.getMessage());
    e.printStackTrace();
    }
}

当问题再次出现时,我发现句柄占用在增加。以下是我执行命令“lsof -p PROGRAM_PID”的消息

java    27439 root   66u  unix 0xffff8103473fb6c0             10151765 socket
java    27439 root   67u  unix 0xffff8103473fb6c0             10151765 socket
java    27439 root   68u  unix 0xffff8103473fb6c0             10151765 socket
java    27439 root   69r  FIFO                0,6             10151917 pipe
java    27439 root   70w  FIFO                0,6             10151917 pipe
java    27439 root   71r  0000               0,11          0  10151918 eventpoll
java    27439 root   72r  FIFO                0,6             10151919 pipe
java    27439 root   73w  FIFO                0,6             10151919 pipe
java    27439 root   74r  0000               0,11          0  10151920 eventpoll
java    27439 root   75u  unix 0xffff8103473fb6c0             10151765 socket
java    27439 root   76u  unix 0xffff8103473fb6c0             10151765 socket
java    27439 root   77r  FIFO                0,6             10152042 pipe
java    27439 root   78w  FIFO                0,6             10152042 pipe
java    27439 root   79r  0000               0,11          0  10152043 eventpoll
java    27439 root   80r  FIFO                0,6             10152044 pipe
java    27439 root   81w  FIFO                0,6             10152044 pipe
java    27439 root   82r  0000               0,11          0  10152045 eventpoll
java    27439 root   83u  unix 0xffff8103473fb6c0             10151765 socket
java    27439 root   84r  FIFO                0,6             10154168 pipe
java    27439 root   85w  FIFO                0,6             10154168 pipe
java    27439 root   86r  0000               0,11          0  10154169 eventpoll
java    27439 root   87r  FIFO                0,6             10154170 pipe

句柄数(管道套接字事件池)将多达数千个。

我尝试了很多方法来避免这种情况,但都失败了。任何人都可以告诉我上述程序中的缺陷吗?

4

3 回答 3

6

您没有关闭输入阅读器。它应该被关闭。

作为一般规则,您应该在一个finally块中关闭资源。

finally在这种情况下,您应该在一个块中关闭输入和输出阅读器。

于 2011-11-11T09:43:35.660 回答
2

如果您还没有找到解决方案,值得检查此线程:

Android - HttpUrlConnection 没有关闭。最终结果为 SocketException

这与 Jellybean 中的“Keep-Alive”连接有关。希望有帮助

于 2014-08-05T10:23:31.397 回答
0

尝试使用OkHttp代替。

我为此苦苦挣扎了几个小时/几天/几周,做所有你想做的事情,设置小的读取/连接超时,并使用一个finally块来关闭连接、输入流、输出流等。但我们从来没有找到一个可行的解决方案。似乎HttpsUrlConnection在某些方面存在缺陷。

所以我们尝试OkHttp作为替代品HttpsUrlConnection,瞧!它开箱即用。

所以,如果你正在努力解决这个问题并且很难修复它,我建议你也尝试使用 OkHttp。

以下是基础知识:

添加 Maven 依赖项后,您可以执行以下操作来下载文件:

OkHttpClient okHttpClient = new OkHttpClient.Builder().build();

OutputStream output = null;

try {
  Request request   = new Request.Builder().url( download_url ).build();
  Response response = okHttpClient.newCall( request ).execute();

  if ( !response.isSuccessful() ) {
    throw new FileNotFoundException();
  }

  output = new FileOutputStream( output_path );

  output.write( response.body().bytes() );
}
finally {
  // Ensure streams are closed, even if there's an exception.
  if ( output != null ) output.flush();
  if ( output != null ) output.close();
}

切换到 OkHttp 立即修复了我们泄露的文件描述符问题,因此如果您遇到困难,值得尝试,即使以添加另一个库依赖项为代价。

于 2019-10-05T19:40:15.357 回答