Java简单代码:java.net.SocketException:服务器意外关闭连接

57

我在Java中编写了一些简单的代码,这个方法应该连接到网站并返回BufferedReader。

private BufferedReader getConnection(String url_a) {
        URL url;
        try {
            System.out.println("getting connection");
            url = new URL(url_a);
            HttpURLConnection urlConnection = (HttpURLConnection) 
                     url.openConnection();
            urlConnection.addRequestProperty("User-Agent",
                    "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.7.3) Gecko/20040924"
                     + "Epiphany/1.4.4 (Ubuntu)");
            inStream = new InputStreamReader(urlConnection.getInputStream());
            return new BufferedReader(inStream);
        } catch (Exception ex) {
            Logger.getLogger(Reader.class.getName()).log(Level.SEVERE, null, ex);
        }
        return null;

}

当我在我的PC上使用它时,它运行良好,但是当我将.jar文件放到服务器上时,我会收到这个错误:

java.net.SocketException: Unexpected end of file from server
at sun.net.www.http.HttpClient.parseHTTPHeader(HttpClient.java:718)
at sun.net.www.http.HttpClient.parseHTTP(HttpClient.java:579)
at sun.net.www.http.HttpClient.parseHTTPHeader(HttpClient.java:715)
at sun.net.www.http.HttpClient.parseHTTP(HttpClient.java:579)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1322)
at dataconverter.Reader.getConnection(Reader.java.260)

问题非常奇怪,因为异常并不总是抛出,有时一切正常,程序运行良好。

有人有什么想法吗?

8个回答

84
"Unexpected end of file" 表示远程服务器接受并关闭连接,但未发送响应。可能是远程系统过于忙碌而无法处理请求,或者存在网络故障导致随机断开连接。
也有可能是服务器中存在错误:请求中的某些内容引起了内部错误,并且服务器关闭连接而不是像应该做的发送 HTTP 错误响应。一些人建议这是由于请求中缺少头信息或头信息值无效而引起的。
根据现有信息,很难确定出现了什么问题。如果您可以访问相关的服务器,则可以使用数据包嗅探工具查找实际发送和接收的内容,并查看服务器进程记录以查看是否存在任何错误消息。

我正在使用Socks服务器进行类似的调用。问题可能出在Socks服务器还是远程服务器? - Dejell
1
可能是两者之一。但SOCKS代理似乎更有可能出现错误,因此我建议先从它开始排查。 - Joni
1
当很多人说错误很可能是由于不正确的标题时,那么为什么错误有时只会出现?为什么不正确的标题也经常被接受? - Yannick Mussche

64

概述

当你期望接收一个响应,但是套接字被突然关闭时,就会遇到这个异常。

详细说明

HTTPClient 是 Java 中的一个类,它在 这里 找到。在特定情况下,它会抛出一条信息为 "Unexpected end of file from server" 的 SocketException 异常。

在发起请求后,HTTPClient 获得了与该请求相关联的套接字的输入流。然后,它会反复轮询该输入流,直到它遇到以下情况之一:

  1. 找到字符串 "HTTP/1."
  2. 读取到 8 个字符之前就达到了输入流的结尾
  3. 找到了除 "HTTP/1." 以外的其他字符串

对于情况 2,如果 HTTP 方法是 CONNECT 或者 HTTP 方法是 POST 且客户端设置了流模式,则 HTTPClient 将抛出该 SocketException 异常。

为什么会发生这种情况呢?这表明 TCP 套接字在服务器能够发送响应之前已被关闭。这可能是由于以下任何原因引起的:

  • 网络连接中断
  • 服务器决定关闭连接
  • 位于客户端和服务器之间的某些设备(如 nginx,路由器等)终止了请求

注意:当Nginx重新加载其配置时,它会强制关闭所有正在进行的HTTP Keep-Alive连接(即使是POST请求),从而导致出现此错误。


5

如果我没有设置身份验证标头或者设置了错误的凭据,就会出现此错误。


2

在我的情况下,只需将代理传递到连接即可解决问题。感谢@Andreas Panagiotidis

Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("<YOUR.HOST>", 80)));
HttpsURLConnection con = (HttpsURLConnection) url.openConnection(proxy);

我的情况也与代理有关。我们的代理设置在公司外的所有连接中使用代理服务器,但对于内部地址不需要代理。在我的JAVA_OPTS中添加了noproxy选项后,连接成功了。JAVA_OPTS=-Dhttps.proxyHost=acme-proxy.global.acme.net -Dhttps.proxyPort=2011 -Dhttp.nonProxyHosts="*.acme.net" - Ioannis K. Moutsatsos

1
我建议使用Wire Shark跟踪数据包。如果您使用的是Ubuntu,请使用sudo-apt get wireshark命令安装。正如Joni所说,找出问题所在的唯一方法是跟随GET请求及其相关响应。

http://www.wireshark.org/download.html


0
在我的情况下,URL 包含了错误的字符,例如空格。总体来说,记录您的 URL,并在某些情况下使用浏览器。

-1

很可能您设置的标题不正确或不可接受。

例如:

connnection.setRequestProperty("content-type", "application/json");

当你说错误头文件最有可能是原因时,为什么错误有时候只会出现呢?为什么错误的头文件也经常被接受呢? - Yannick Mussche

-2

我也遇到了这个异常。我的错误代码如下:

        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
    connection.setRequestMethod(requestMethod);
        connection.setRequestProperty("Content-type", "JSON");

我发现 "Content-type" 不应该是 "JSON",这是错误的!我通过将此行更新为以下内容来解决此异常。
        connection.setRequestProperty("Content-type", "application/json");

你可以检查你的“Content-type”


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接