ftp-pool
ftp-pool copied to clipboard
linux环境:java.net.SocketException: Broken pipe (Write failed)
java.net.SocketException: Broken pipe (Write failed) at java.net.SocketOutputStream.socketWrite0(Native Method) at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:109) at java.net.SocketOutputStream.write(SocketOutputStream.java:153) at sun.nio.cs.StreamEncoder.writeBytes(StreamEncoder.java:221) at sun.nio.cs.StreamEncoder.implFlushBuffer(StreamEncoder.java:291) at sun.nio.cs.StreamEncoder.implFlush(StreamEncoder.java:295) at sun.nio.cs.StreamEncoder.flush(StreamEncoder.java:141) at java.io.OutputStreamWriter.flush(OutputStreamWriter.java:229) at java.io.BufferedWriter.flush(BufferedWriter.java:254) at org.apache.commons.net.ftp.FTP.__send(FTP.java:545) at org.apache.commons.net.ftp.FTP.sendCommand(FTP.java:519) at org.apache.commons.net.ftp.FTP.sendCommand(FTP.java:648) at org.apache.commons.net.ftp.FTP.cwd(FTP.java:868) at org.apache.commons.net.ftp.FTPClient.changeWorkingDirectory(FTPClient.java:1167) at com.yinghuo.contract.biz.core.util.ftp.FtpClientTemplate.uploadFile(FtpClientTemplate.java:56)
在linux 环境下容易出现session超时。需要保证keepAlive
抱歉现在才看到,能否提供更详细的信息,比如是否在多线程环境下,或者文件是否过大,ftp服务器的配置之类的。 我改动了下代码,增加了配置ftp.client.keepAliveTimeout=30,不知道是否能解决你出现的问题,源码为: /** * Set the time to wait between sending control connection keepalive messages * when processing file upload or download. * * @param controlIdle the wait (in secs) between keepalive messages. Zero (or less) disables. * @since 3.0 * @see #setControlKeepAliveReplyTimeout(int) */ public void setControlKeepAliveTimeout(long controlIdle){ __controlKeepAliveTimeout = controlIdle * 1000; }
not help
谢谢,我重新尝试下;我配置了这个参数,没看你底层实现 @jayknoxqu
这是我的配置 ftpClient.setControlKeepAliveTimeout(ftpClientConfig.getControlKeepAliveTimeout());
应该是服务器端口被关闭了,目前没有其他办法。
https://stackoverflow.com/questions/51730863/ftpclient-how-to-get-around-org-apache-commons-net-io-copystreamexception-ioexc 看了下,还没想到很好的办法 @jayknoxqu
你不会是sftp吧?
你不会是sftp吧?
还真不是,就是普通的FTP。我不使用池化的方法还行,但是一起用池化的;就 at org.apache.commons.net.ftp.FTPClient.changeWorkingDirectory(FTPClient.java:1167) 最后看到底层还是那个流 flush 异常
"我不使用池化的方法还行,但是一起用池化的",能具体描述下么我这边没办法复现出来,是像测试类里那样使用么?
"我不使用池化的方法还行,但是一起用池化的",能具体描述下么我这边没办法复现出来,是像测试类里那样使用么?
多线程一次性发送100张图片到FTP服务器,使用FTPClientPool就会出现了;如果是使用 new FTPClient不会出现这种情况
你能贴下代码么? https://github.com/jayknoxqu/ftp-pool/blob/master/src/test/java/com/zhenjin/ftp/FtpClientPoolTest.java
FtpClientPool是标记为不弃用的; 正确使用连接池的方式是使用commons-pool2 提供的
GenericObjectPool<FTPClient> ftpClientPool=new GenericObjectPool<>(ftpClientFactory);
方法创建连接池
你能贴下代码么? https://github.com/jayknoxqu/ftp-pool/blob/master/src/test/java/com/zhenjin/ftp/FtpClientPoolTest.java
/**
-
@author marvinYu
-
用于测试 ftpClientTemplate:uploadFile 在Linux环境下与windows下面是否有区别
-
@version : LinuxFTPUploadTestJob.java, v 0.1 2019-02-13 18:01 Exp $ */ @JobHandler(value = "linuxFTPUploadTestJob") @Service public class LinuxFTPUploadTestJob extends AbstractJobHandler { @Resource private FtpClientTemplate ftpClientTemplate;
@Override public ReturnT<String> doExecute(String s) throws Exception { int linuxFtpUploadSize = Integer.parseInt(SysConfigUtil .getSysConfigByType("linux_ftp_upload_size"));
for (int i = 0; i < linuxFtpUploadSize; i++) { Runnable runnable = () -> { File file = new File( "/usr/local/test.properties"); boolean uploadResult = ftpClientTemplate.uploadFile(file, "/upload"); String threadName = Thread.currentThread().getName(); System.out.println("Thread 1-" + threadName + ":" + uploadResult); }; runnable.run(); Thread testThread = new Thread(runnable); testThread.start(); } return ReturnT.SUCCESS;
} }
JobHandler(xxxJob调度) 在Linux环境下定时周期1分钟,就可以看到后台有该异常
FtpClientPool是标记为不弃用的; 正确使用连接池的方式是使用commons-pool2 提供的
GenericObjectPool<FTPClient> ftpClientPool=new GenericObjectPool<>(ftpClientFactory);
方法创建连接池
这个没有问题,我看了common-pool的实现是一致的。
@jayknoxqu
windows环境下,长期观察下。就可以看到这个 org.apache.commons.net.ftp.FTPConnectionClosedException: FTP response 421 received. Server closed connection. at org.apache.commons.net.ftp.FTP.__getReply(FTP.java:388) at org.apache.commons.net.ftp.FTP.__getReply(FTP.java:300) at org.apache.commons.net.ftp.FTP.sendCommand(FTP.java:523) at org.apache.commons.net.ftp.FTP.sendCommand(FTP.java:648) at org.apache.commons.net.ftp.FTP.cwd(FTP.java:868) at org.apache.commons.net.ftp.FTPClient.changeWorkingDirectory(FTPClient.java:1167) at com.yinghuo.fundgateway.util.ftp.FtpClientTemplate.uploadFile(FtpClientTemplate.java:51) at com.yinghuo.fundgateway.biz.task.job.temp.LinuxFTPUploadTestJob.lambda$doExecute$0(LinuxFTPUploadTestJob.java:41) at java.lang.Thread.run(Thread.java:745)
public FtpClientTemplate(FtpClientFactory ftpClientFactory) { this.ftpClientPool = new GenericObjectPool<>(ftpClientFactory); this.ftpClientPool.setTestOnBorrow(true); this.ftpClientPool.setTestOnCreate(true); this.ftpClientPool.setTestOnReturn(true); this.ftpClientPool.setTestWhileIdle(true); this.ftpClientPool.setMinEvictableIdleTimeMillis(60000); }
加了这个之后,看到异常堆栈。校验到Connection已经异常了 @jayknoxqu 对比了下,目前这个按照common-pool实现还是有很多优化空间。可能要像C3P0那样对于GenericObjectPool 处理下更适用于生产环境
six six six
写的太假了,自己写都比你那个强
写的太假了,自己写都比你那个强
写的挺好的,还需要考虑的点还有很多而已。这个目前还是一个待完善版本,类似于 http://commons.apache.org/proper/commons-pool/examples.html
非常感谢你提出了这么多问题, FTP response 421 received这个问题我也检测出来了,感觉应该是保活的问题 GenericObjectPool确实是需要优化下
应该的,互相学习。应该是保活机制不完善,连接池没有对于池中连接进行有效性处理以及外部服务,网络抖动都可能导致这些失效。
写的太假了,自己写都比你那个强 @fortunelee 这个用于生产确实有问题,此项目主要是为了教学,让参与这个项目的人了解并熟悉连接池 ,通过这个项目你应该掌握: 1.连接池的基本方法和调用流程, 2.Queue对列的基本用法.有界对列,无界对列等相关概念, ...
Redis 的客户端 Jedis也是通过GenericObjectPool来实现的
public JedisPool(final String host) {
URI uri = URI.create(host);
if (JedisURIHelper.isValid(uri)) {
String h = uri.getHost();
int port = uri.getPort();
String password = JedisURIHelper.getPassword(uri);
int database = JedisURIHelper.getDBIndex(uri);
boolean ssl = uri.getScheme().equals("rediss");
this.internalPool = new GenericObjectPool<Jedis>(new JedisFactory(h, port,
Protocol.DEFAULT_TIMEOUT, Protocol.DEFAULT_TIMEOUT, password, database, null,
ssl, null, null, null), new GenericObjectPoolConfig());
} else {
this.internalPool = new GenericObjectPool<Jedis>(new JedisFactory(host,
Protocol.DEFAULT_PORT, Protocol.DEFAULT_TIMEOUT, Protocol.DEFAULT_TIMEOUT, null,
Protocol.DEFAULT_DATABASE, null, false, null, null, null), new GenericObjectPoolConfig());
}
}
可看下它具体是怎么来实现的,
@jayknoxqu 就你玩的花哨
在检测到对象失效的时候,重新登录连接上ftp服务器,在放回对象池
试下这几个参数,每次获取一个连接,返还一个连接都测试 一下是否是可用的状态 ,如果不是会自动删除并重建,然后获取下一个 pool.setTestOnBorrow(true); pool.setTestWhileIdle(true); pool.setTestOnReturn(true);
有更强的版本吗?从池中获取的client可能是断开的。导致程序异常。
@fortunelee 楼主写的这个挺好的,思想不错,pool2这个思想的确值得学习。但是FTP这个协议的确很复杂,数据口和控制口是两个socket,而且还要根据具体的FTP server端去配置client。兄台你这个头像挺骚气啊
Dear email is ok!