java.net.UnknownHostException和java.net.SocketException:打开的文件太多

时间:2013-04-10 05:07:55

标签: java linux servlets

我在Tomcat上运行Web应用程序。我的应用程序连接到其他Web服务以满足客户端的请求。有时我在打开URL连接时得到java.net.UnknownHostException,然后有时我开始得到java.net.SocketException:打开的文件太多了。我的服务器停止接受连接。请指导。

String  response;
    HttpURLConnection conn = null;
BufferedReader rd = null;
InputStream in = null;
try
{
    // Send data
    String urlStr = URL;
    URL url = new URL(urlStr);
    conn = (HttpURLConnection)url.openConnection();
    conn.setRequestProperty("content-type", "application/x-www-form-urlencoded");
    int contentLength = conn.getContentLength();
    //   System.out.println("content length 1" +  contentLength);
    if (contentLength <= 0)
    {
        InputStream in1 = (conn).getErrorStream();
        if (in1 != null)
        {
            in1.close();
        }
        conn.getInputStream().close();
        in = null;
        conn.disconnect();
        conn = null;
        return null;
    }
    in = conn.getInputStream();
    if (conn.getResponseCode() != 200)
    {
        InputStream in1 = (conn).getErrorStream();
        if (in1 != null)
        {
            in1.close();
        }
        conn.getInputStream().close();
        in = null;
        conn.disconnect();
        conn = null;
        in.close();
        in = null;
        return null;
    }
    // Get the response
    rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
    StringBuffer stringBuffer = new StringBuffer();
    String line = null;
    while ((line = rd.readLine()) != null)
    {
        stringBuffer.append(line);
    }
    response = stringBuffer.toString();
    System.out.println("full ads response = " + response);
}
catch (Exception ex)
{
    //   ex.printStackTrace();
}
finally
{
    try
    {
        if (conn != null)
        {
            InputStream in1 = (conn).getErrorStream();
            if (in1 != null)
            {
                in1.close();
            }
            conn.getInputStream().close();
            in = null;
            conn.disconnect();
            conn = null;
        }
        if (rd != null)
        {
            rd.close();
            rd = null;
        }
        if (in != null)
        {
            in.close();
            in = null;
        }
    }
    catch (Exception e)
    {
    }
}
return null;        

4 个答案:

答案 0 :(得分:2)

UnknownHostException只是表示您使用的URL是指不存在的主机名,或者可能是主机名的DNS记录或系统在该时刻处于转换状态。

套接字泄漏可能是由下面的过多清理代码引起的,请参阅注释。

当你压制所有异常时,你不会对哈迪斯有任何希望找出问题所在。所以这是第一件要解决的问题。永远不要忽视异常记录它们。打印堆栈跟踪。做点什么。

然而,您的代码还有许多其他问题:

HttpURLConnection conn = null;
BufferedReader rd = null;
InputStream in = null;
try
{
    // Send data
    String urlStr = URL;

这个变量是多余的。只需使用下面的URL

    URL url = new URL(urlStr);
    conn = (HttpURLConnection)url.openConnection();
    conn.setRequestProperty("content-type", "application/x-www-form-urlencoded");

目前为止确定。

    int contentLength = conn.getContentLength();
    //   System.out.println("content length 1" +  contentLength);
    if (contentLength <= 0)

检查零内容长度是非常不寻常的。这是检查错误的代理吗?我只想删除这个测试。

    {
        InputStream in1 = (conn).getErrorStream();
        if (in1 != null)
        {
            in1.close();
        }
        conn.getInputStream().close();
        in = null;
        conn.disconnect();
        conn = null;
        return null;
    }

以上所有内容都是多余的。你已经在finally块中拥有它了。删除它。

    in = conn.getInputStream();
    if (conn.getResponseCode() != 200)

现在就是如何检查错误。但是,您必须在之前调用getResponseCode() ,然后调用getInputStream(),,否则后者可能会在您对响应代码为404感兴趣时抛出FileNotFoundException

    {
        InputStream in1 = (conn).getErrorStream();
        if (in1 != null)
        {
            in1.close();
        }
        conn.getInputStream().close();
        in = null;
        conn.disconnect();
        conn = null;
        in.close();
        in = null;
        return null;
    }

同样,以上所有内容都是多余的。你已经在finally块中拥有它了。删除它。

    // Get the response
    rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
    StringBuffer stringBuffer = new StringBuffer();
    String line = null;

line的初始化是多余的。变量在下一行中分配。删除它。

    while ((line = rd.readLine()) != null)
    {
        stringBuffer.append(line);
    }
    response = stringBuffer.toString();
    System.out.println("full ads response = " + response);
}
catch (Exception ex)

你应该只在这里抓住IOException

{
    //   ex.printStackTrace();

从不忽略例外。

}
finally
{
    try
    {
        if (conn != null)
        {
            InputStream in1 = (conn).getErrorStream();
            if (in1 != null)
            {
                in1.close();
            }

您无需获取或关闭错误流。删除所有这些。

            conn.getInputStream().close();
            in = null;

将此变量设置为null是没有意义的。它是一个局部变量,所以它无论如何都会超出范围。

            conn.disconnect();
            conn = null;

同上。

        }
        if (rd != null)
        {
            rd.close();
            rd = null;
        }

您已经关闭了输入流。这是多余的。删除此块。

        if (in != null)
        {
            in.close();
            in = null;
        }

您已经关闭了连接的输入流。这都是多余的。删除它。

    }
    catch (Exception e)
    {
    }

同样,你应该只在这里捕捉IOException,你不应该忽略错误。就个人而言,我会抛出方法IOException并且根本没有任何catch块。返回null对调用者来说并不是很有用。他通常会更好地知道到底出了什么问题,这样他就可以做出有用的决定。

}
return null;        

答案 1 :(得分:0)

尝试增加linux服务器打开文件限制以修复java.net.SocketException: Too many open files。 max文件的限制存储在linux中的这个文件中:

/proc/sys/fs/file-max

要检查当前打开的文件,可以使用:

lsof

检查否。打开文件,使用:

lsof | wc -l

另外,除了conn.disconnect()之外,关闭你的连接conn.close()。确保您也关闭了inputreader。所有这些关闭都应该在finally块中,以便在出现任何异常时也关闭连接。

答案 2 :(得分:0)

你在Windows或Linux上运行吗?查看这篇文章,希望它有所帮助:http://edmund.haselwanter.com/en/blog/2009/03/13/tomcat-too-many-open-files/

答案 3 :(得分:0)

我最近在尝试与无法访问的URL建立大量连接时遇到了此问题。连接会因UnknownHostException而失败,但最终会因java.net.SocketException而失败:打开的文件太多。

问题是,底层的本机套接字句柄是由HttpURLConnection创建的。似乎直到对象被垃圾回收后才释放该句柄。就我而言,没有足够的内存来触发垃圾回收。如果GC从未运行,则不会释放本机句柄。

我的解决方案是在获取UnknownHostExceptions时定期调用System.gc()。我知道这似乎有点麻烦,但是它奏效了,底层的本机句柄被释放,问题消失了。