S3 Java客户端因“内容长度分隔的邮件正文过早结束”或“java.net.SocketException Socket closed”而失败了很多

时间:2012-03-31 03:35:23

标签: java sockets amazon-s3 connection amazon-web-services

我有一个应用程序在S3上做了很多工作,主要是从它下载文件。我看到很多这类错误,我想知道这是否是我的代码上的内容,或者服务是否真的不可靠。

我用来从S3对象流中读取的代码如下:

public static final void write(InputStream stream, OutputStream output) {

  byte[] buffer = new byte[1024];

  int read = -1;

  try {

    while ((read = stream.read(buffer)) != -1) {
      output.write(buffer, 0, read);
    }

    stream.close();
    output.flush();
    output.close();
  } catch (IOException e) {
    throw new RuntimeException(e);
  }

}

OutputStream 新的BufferedOutputStream(新的FileOutputStream(文件))。我正在使用最新版本的Amazon S3 Java客户端,并且在放弃之前重试四次次。因此,在尝试了4次后,它仍然失败。

有关如何改善这一点的任何提示或提示都表示赞赏。

6 个答案:

答案 0 :(得分:15)

我设法克服了一个非常类似的问题。在我的情况下,我得到的例外是相同的;它发生在较大的文件上,但不适用于小文件,而且在单步执行调试器时根本不会发生。

问题的根本原因是AmazonS3Client对象在下载过程中收集了垃圾,导致网络连接中断。之所以发生这种情况,是因为我每次调用加载文件时都在构建一个新的AmazonS3Client对象,而首选的用例是创建一个持久的客户端对象,它可以在整个调用过程中存活 - 或者至少保证在整个调用过程中存在。下载。因此,简单的补救措施是确保保留对AmazonS3Client的引用,以便它不会得到GC。

帮助我的AWS论坛上的链接位于:https://forums.aws.amazon.com/thread.jspa?threadID=83326

答案 1 :(得分:3)

网络正在关闭连接,在客户端获取所有数据之前,由于某种原因,这就是正在发生的事情。

任何HTTP请求的一部分是内容长度,你的代码正在获取标题,说嘿好友,这里的数据,以及它的大部分......然后在客户端读取所有数据之前连接正在下降..所以它的爆炸除外。

我会查看您的OS / NETWORK / JVM连接超时设置(尽管在这种情况下JVM通常会从操作系统继承)。关键是弄清楚网络的哪个部分导致了问题。这是你的计算机级别设置说,nope不会再等待数据包..是你使用非阻塞读取,在你的代码中有一个超时设置,它说,嘿,没有得到来自服务器的任何数据都比我应该等待的时间长,所以我要删除连接和异常。等等等。

最好的选择是低级监听数据包流量并向后追踪,查看连接丢失的位置,或者查看是否可以在可以控制的事物(例如软件和OS / JVM)中超时。

答案 2 :(得分:1)

首先,如果(并且仅当)您在自己和Amazon S3之间遇到连接问题,您的代码将完全正常运行。正如Michael Slade points out所示,标准的连接级调试建议适用。

关于你的实际源代码,我注意到你应该注意的一些代码气味。直接在源代码中注释它们:

public static final void write(InputStream stream, OutputStream output) {

  byte[] buffer = new byte[1024]; // !! Abstract 1024 into a constant to make 
                                  //  this easier to configure and understand.

  int read = -1;

  try {

    while ((read = stream.read(buffer)) != -1) {
      output.write(buffer, 0, read);
    }

    stream.close(); // !! Unexpected side effects: closing of your passed in 
                    //  InputStream. This may have unexpected results if your
                    //  stream type supports reset, and currently carries no 
                    //  visible documentation.

    output.flush(); // !! Violation of RAII. Refactor this into a finally block, 
    output.close(); //  a la Reference 1 (below).

  } catch (IOException e) {
    throw new RuntimeException(e); // !! Possibly indicative of an outer 
                                   //   try-catch block for RuntimeException. 
                                   //   Consider keeping this as IOException.
  }
}

Reference 1

否则,代码本身似乎很好。在您连接到变幻无常的远程主机的情况下,应该预期会出现IO异常,并且您最好的做法是在这些方案中草拟一个理智的策略来缓存和重新连接。

答案 3 :(得分:0)

  1. 尝试使用wireshark查看发生这种情况时电线上发生的情况。

  2. 尝试使用您自己的网络服务器暂时替换S3,然后查看问题是否仍然存在。如果它确实是你的代码而不是S3。

  3. 它是随机的这一事实表明您的主机与某些S3主机之间存在网络问题。

答案 4 :(得分:0)

根据我的经验,S3也可以关闭慢速连接。

答案 5 :(得分:0)

我会仔细查看离您的客户端应用程序最近的网络设备。这个问题有些网络设备在您和服务之间丢弃数据包。查看问题首次出现时是否有起点。是否有任何更改,如路由器的固件更新或在那个时间更换交换机?

根据从ISP购买的金额验证您的带宽使用情况。是否有一天你接近这个限制?你能获得带宽使用情况的图表吗?查看过早终止是否可以与高带宽使用相关联,特别是如果它接近某个已知限制。问题似乎是在较小的文件和大文件上选择它们几乎完成下载?从ISP购买更多带宽可能会解决问题。