解决FTPClient下载网络文件线程挂起问题

今天在windows上调试FTP下载文件时,出险线程假死,代码如下:

if (inputStream != null) {
                byte[] data = null;
                ByteArrayOutputStream outStream = new ByteArrayOutputStream();
                data = new byte[inputStream.available()];
                int len = 0;
                while ((len = inputStream.read(data)) != -1) {
                    outStream.write(data, 0, len);
                }
                data = outStream.toByteArray();
                Base64.Encoder encoder = Base64.getEncoder();
                re = encoder.encodeToString(data);
            }  

通过打印日志排查到while死循环,查看read方法源码注释:

/* <p> If the length of <code>b</code> is zero, then no bytes are read and
     * <code>0</code> is returned; otherwise, there is an attempt to read at
     * least one byte. If no byte is available because the stream is at the
     * end of the file, the value <code>-1</code> is returned; otherwise, at
     * least one byte is read and stored into <code>b</code>.
*/
public int read(byte b[]) throws IOException {
return read(b, 0, b.length);
}

在date字节数组长度为1时,read方法返回0,while出现死循环,原因是因为网络传输数据不及时,导致inputStream.available()方法未取到本地内存的字节数据返回0。

由于下载的文件大小不是很大,默认给了一个2048大小的字节数组,于是做了以下优化:

if (inputStream != null) {
                byte[] data = null;
                ByteArrayOutputStream outStream = new ByteArrayOutputStream();
                if (inputStream.available() == 0) {
                    data = new byte[2048];
                } else {
                    data = new byte[inputStream.available()];
                }

                int len = 0;
                while ((len = inputStream.read(data)) != -1) {
                    outStream.write(data, 0, len);
                }
                data = outStream.toByteArray();
                Base64.Encoder encoder = Base64.getEncoder();
                re = encoder.encodeToString(data);
            } 

  再次调试,问题解决。

但是,在将程序部署到Linux服务器上依然假死,

问题分析:

FTPClient调用retrieveFileStream线程假死

FTPClient.listFiles()或者FTPClient.retrieveFile()方法时,就停止在那里,什么反应都没有,出现假死状 态。于是各种网上资料查找

FTP的两种传输模式:主动模式被动模式

在调用这两个方法之前,调用 FTPClient.enterLocalPassiveMode();这个方法的意思就是每次数据连接之前,ftp client告诉ftp server开通一个端口来传输数据。因为ftp server可能每次开启不同的端口来传输数据,但是在linux上,由于防火墙安全限制,可能某些端口没有开启,所以就出现阻塞。

解决方法:ftpClient.enterLocalPassiveMode(); //开启本地被动模式,此代码设置在登陆之后或者之前都可以。

同样,如果上传的话需要enterRemotePassiveMode()//开启远程被动传输模式

感谢网络上的大神们的分享,不然又得钻牛角了。

posted @ 2021-09-13 10:40  迷路的棉花糖  阅读(609)  评论(0编辑  收藏  举报