读取S3文件时出现"java.net.SocketException: Socket is closed"错误

8
我正在尝试从S3读取一个csv文本文件,然后将其每一行发送到分布式队列中进行处理。
在尝试读取时,我会在不同的执行点上收到“java.net.SocketException:Socket is closed”异常。这是代码:
      AmazonS3 s3 = new AmazonS3Client(new PropertiesCredentials(MyClass.class.getResourceAsStream("myCredentials.properties")));

        String bucketName = "myBucket";
        String key = "myFile";  

        S3Object object = s3.getObject(new GetObjectRequest(bucketName, key));

        InputStream in = object.getObjectContent();

        BufferedReader readerS3 = new BufferedReader(new InputStreamReader(in, Charset.forName(fileInfo.getEncoding())));

        try {
            String line = null;
            while ((line = readerS3.readLine()) != null) {
                // Sending the line to a distributed queue
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                in.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

有没有想法解决这个问题?

更新:

如果我停止整个程序并再次运行它,那么第二次运行该方法时就会出现此异常,但是如果我再次运行该方法,则第一次运行该方法时它可以正常工作。


2
尝试在保留对这些对象的显式引用的情况下运行此代码(如果尚未尝试过且正在使用)。这些对象包括:S3ClientS3ObjectAmazonS3Client。可能存在垃圾回收器无法及时清理对象并关闭连接的问题。 - jn1kk
2
文件有多大?也许你需要更改套接字超时时间(也许是0?->无限制)?http://docs.amazonwebservices.com/AWSJavaSDK/latest/javadoc/com/amazonaws/ClientConfiguration.html#getSocketTimeout() - jn1kk
2
错误的URL(无法编辑评论),正确的URL-> http://tinyurl.com/d75xffa - jn1kk
1
本地变量不受GC的影响。它们所指向的对象是受影响的。你在某个地方过早地关闭了套接字。这是你代码中的一个错误,而不是服务器或网络问题。 - user207421
@jsn 更改读取超时时间不会解决这个问题。你似乎只是在猜测。 - user207421
显示剩余8条评论
7个回答

6

如评论中的“jsn”所建议,问题在于您需要使用ClientConfiguration配置AmazonS3

ClientConfiguration config = new ClientConfiguration();
config.setSocketTimeout(0);
AmazonS3 s3 = new AmazonS3Client(/* credentials */, config);

无限超时的缺点是什么? - om-nom-nom

2

谢谢@jsn,你的建议解决了我的问题。

我有一个返回InputStream的方法,因为AmazonS3对象被垃圾收集器回收,所以导致InputStream关闭。

我现在让它保持对AmazonS3对象的引用,这解决了我的问题。


你能举个例子说明如何保持引用吗? - 2Big2BeSmall
创建一个类变量,如下所示,并将其设置为private final AmazonS3 s3; - Sarel Botha

1
也许你应该在finally中关闭readerS3而不是'in'。也就是说,关闭最外层的对象,它可以关闭其包装的子对象。
如果你首先关闭'in',那么InputStreamReader和BufferedReader仍然是打开的,如果它们试图对它们包装的对象进行任何操作,那么它已经被关闭了。

1
关闭套接字的输入流或输出流,或者任何包装它们的流/读取器/写入器包装器,都会关闭套接字(因此分别关闭输出或输入流)。

但是在循环执行期间没有关闭任何流/读取器/写入器。 - Fgblanch
@Fgblanch 在循环执行之后关闭,但在下一次调用该方法之前关闭。或者您在其他地方关闭了套接字或其流之一。 - user207421

0

无需不断重新初始化s3。

在onCreate中调用初始化s3Object和s3Client的函数。

然后在您的异步任务中只需使用该调用即可。

通过这种方式,当进行while读取时,您的s3Client将保持相同的数据并且永远不会关闭与s3的套接字连接。聪明点,学习一下。

S3Client s3Client;
S3Object s3Object;

onCreate() {
 s3Client = new AmazonS3Client(new BasicSessionCredentials(Constants.ACCESS_KEY_ID, Constants.SECRET_KEY, Constants.TOKEN));

 object = new S3Object();
}

doinbackground() {
      object = s3Client.getObject(new GetObjectRequest(Constants.getBucket(), id +".png"));
 }

0
在我的情况下,我由于JVM内存使用过高而遇到了这个错误。
减少应用程序的内存使用或增加JVM可用的内存可以解决这个问题。

0

我曾经遇到过同样的问题,这个主题帮助我解决了这个问题:S3 Java客户端在“Content-Length delimited message body”或“java.net.SocketException Socket closed”中经常失败

基本上,我为每个文件创建了一个新的S3Client对象,但在某一点上,这个对象被垃圾回收了。所以,我将我的类转换为使用单例模式:

private static AmazonS3 s3Client;
  static {
    s3Client = new AmazonS3Client(new BasicAWSCredentials(AWSKey, AWSSecretKey));
  }

  public AmazonS3 getService() {
    return s3Client;
  }

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