有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

S3Java客户端经常失败,出现“ContentLength分隔消息正文过早结束”或“Java.net.SocketExceptionsocket关闭”

我有一个在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);
  }

}

此输出流是一个新的缓冲输出流(新文件输出流(文件))。我正在使用最新版本的AmazonS3Java客户端,在放弃之前,我会重试四次。因此,在尝试了4次之后,它仍然失败

任何提示或提示,我可以如何可能改善这是感激的


共 (6) 个答案

  1. # 1 楼答案

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

    根据从ISP处购买的金额验证带宽使用情况。一天中有没有时间你正在接近极限?你能得到你的带宽使用情况的图表吗?看看过早终止是否与高带宽使用相关,特别是当它接近某个已知极限时。问题似乎只出现在小文件和大文件上,直到它们几乎完成下载时才出现?从ISP购买更多带宽可能会解决此问题

  2. # 2 楼答案

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

    问题的根本原因是AsMaMs3客户端对象在下载过程中被垃圾收集,导致网络连接中断。这是因为我在每次调用加载文件时都在构造一个新的AmazonS3Client对象,而首选的用例是创建一个持久的客户机对象,该对象可以在调用之间存活下来,或者至少可以保证在整个下载过程中存在。因此,简单的补救办法是确保保留对AmazonS3Client的引用,这样它就不会得到GC'd

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

  3. # 3 楼答案

    1. 尝试使用wireshark查看发生这种情况时导线上发生了什么

    2. 尝试用自己的web服务器临时替换S3,看看问题是否仍然存在。如果是这样,那就是你的代码,而不是S3

    这是随机的,这表明您的主机和某些S3主机之间存在网络问题

  4. # 4 楼答案

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

  5. # 5 楼答案

    首先,如果(且仅当)您与AmazonS3之间存在连接问题,则代码运行完全正常。正如michaelsladepoints 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异常应该在连接到易变的远程主机的情况下发生,最好的做法是起草一个合理的策略,以便在这些情况下缓存和重新连接

  6. # 6 楼答案

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

    任何HTTP请求的一部分都是内容长度,您的代码都会得到标题,说嘿,伙计,这是数据,这就是其中的大部分。。然后,在客户端读取所有数据之前,连接正在断开。。所以它的爆炸是例外

    我将查看您的OS/NETWORK/JVM连接超时设置(尽管在这种情况下JVM通常从OS继承)。关键是要找出网络的哪个部分导致了问题。您的计算机级别设置是否会说,不,不再等待数据包。。是因为您使用的是非阻塞读取,代码中有一个超时设置,它表示,嘿,没有从服务器获取任何数据,因为等待的时间超过了我应该等待的时间,所以我将删除连接和异常。等等等等等等

    最好的办法是对数据包流量进行低级别监视并向后跟踪,以查看连接断开发生在何处,或者查看是否可以在可以控制的事情上(如软件和OS/JVM)超时