我有以下每3秒运行一次的操作。基本上,它从服务器下载文件,然后每3秒将其保存到本地文件中。以下代码可以完成一段时间。
public class DownloadTask extends AsyncTask<String, Void, String>{
@Override
protected String doInBackground(String... params) {
downloadCommandFile( eventUrl);
return null;
}
}
private void downloadCommandFile(String dlUrl){
int count;
try {
URL url = new URL( dlUrl );
NetUtils.trustAllHosts();
HttpsURLConnection con = (HttpsURLConnection) url.openConnection();
con.setDoInput(true);
con.setDoOutput(true);
con.connect();
int fileSize = con.getContentLength();
Log.d(TAG, "Download file size = " + fileSize );
InputStream is = url.openStream();
String dir = Environment.getExternalStorageDirectory() + Utils.DL_DIRECTORY;
File file = new File( dir );
if( !file.exists() ){
file.mkdir();
}
FileOutputStream fos = new FileOutputStream(file + Utils.DL_FILE);
byte data[] = new byte[1024];
long total = 0;
while( (count = is.read(data)) != -1 ){
total += count;
fos.write(data, 0, count);
}
is.close();
fos.close();
con.disconnect(); // close connection
} catch (Exception e) {
Log.e(TAG, "DOWNLOAD ERROR = " + e.toString() );
}
}
一切正常,但是如果我让它运行5到10分钟,则会出现以下错误。
06-04 19:40:40.872:E / NativeCrypto(6320):AppData :: create pipe(2)失败:打开文件太多06-04 19:40:40.892:E / NativeCrypto(6320):AppData :: create pipe(2)失败:打开的文件太多06-0419:40:40.892:E / EventService(6320):下载错误=javax.net.ssl.SSLException:无法创建应用程序数据
最近两天我一直在做一些研究。有建议表明它们有许多连接处于打开状态,例如https://stackoverflow.com/a/13990490/1503155,但我仍然无法弄清问题所在。有什么想法可能导致问题吗?预先感谢。
我认为您会收到此错误,因为您同时打开了太多文件,这意味着您同时运行了太多异步任务(每个异步任务都打开了一个文件),如果您说自己每3秒运行一个新的。
您应该尝试使用线程池执行程序来限制同时运行的异步任务的数量。
您的问题没有太多线程,尽管这是导致问题浮出水面的原因。
正如注释中提到的@stdout,除非您另外指定,否则AsyncTask已经在所有AsyncTask中共有并共享的线程池中运行。这里的问题是,文件描述符未及时正确关闭。
问题是您的文件描述符关闭得不够快。
我为此花费了数小时,数天,数周的时间,竭尽所能,设置较小的读取/连接超时,并使用finally
块关闭连接,输入流,输出流等。解。 HttpsUrlConnection
似乎在某种程度上有缺陷。
所以我们尝试用OkHttp
代替HttpsUrlConnection
和瞧!它开箱即用。
因此,如果您对此感到挣扎,并且很难解决它,我建议您也尝试使用OkHttp。
这里是基本知识:
一旦添加了Maven依赖项,您可以执行以下操作来下载文件:
OkHttpClient okHttpClient = new OkHttpClient.Builder().build();
OutputStream output = null;
try {
Request request = new Request.Builder().url( download_url ).build();
Response response = okHttpClient.newCall( request ).execute();
if ( !response.isSuccessful() ) {
throw new FileNotFoundException();
}
output = new FileOutputStream( output_path );
output.write( response.body().bytes() );
}
finally {
// Ensure streams are closed, even if there's an exception.
if ( output != null ) output.flush();
if ( output != null ) output.close();
}
切换到OkHttp会立即解决我们泄漏的文件描述符问题,因此即使您被困,也值得尝试,即使以增加另一个库依赖项为代价。