Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

linux环境:java.net.SocketException: Broken pipe (Write failed) #2

Open
MarvinYu opened this issue Nov 14, 2018 · 27 comments
Open

Comments

@MarvinYu
Copy link

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

@jayknoxqu
Copy link
Owner

抱歉现在才看到,能否提供更详细的信息,比如是否在多线程环境下,或者文件是否过大,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;
}

@fortunelee
Copy link

not help

@MarvinYu
Copy link
Author

MarvinYu commented Nov 22, 2018

谢谢,我重新尝试下;我配置了这个参数,没看你底层实现 @jayknoxqu

这是我的配置 ftpClient.setControlKeepAliveTimeout(ftpClientConfig.getControlKeepAliveTimeout());

应该是服务器端口被关闭了,目前没有其他办法。

@MarvinYu
Copy link
Author

@jayknoxqu
Copy link
Owner

你不会是sftp吧?

@MarvinYu
Copy link
Author

你不会是sftp吧?

还真不是,就是普通的FTP。我不使用池化的方法还行,但是一起用池化的;就
at org.apache.commons.net.ftp.FTPClient.changeWorkingDirectory(FTPClient.java:1167)
最后看到底层还是那个流 flush 异常

@jayknoxqu
Copy link
Owner

"我不使用池化的方法还行,但是一起用池化的",能具体描述下么我这边没办法复现出来,是像测试类里那样使用么?

@jayknoxqu jayknoxqu reopened this Feb 13, 2019
@MarvinYu
Copy link
Author

"我不使用池化的方法还行,但是一起用池化的",能具体描述下么我这边没办法复现出来,是像测试类里那样使用么?

多线程一次性发送100张图片到FTP服务器,使用FTPClientPool就会出现了;如果是使用 new FTPClient不会出现这种情况

@jayknoxqu
Copy link
Owner

jayknoxqu commented Feb 13, 2019

@jayknoxqu
Copy link
Owner

FtpClientPool是标记为不弃用的;
正确使用连接池的方式是使用commons-pool2 提供的

GenericObjectPool<FTPClient> ftpClientPool=new GenericObjectPool<>(ftpClientFactory);

方法创建连接池

@MarvinYu
Copy link
Author

MarvinYu commented Feb 14, 2019

你能贴下代码么?
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 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分钟,就可以看到后台有该异常

@MarvinYu
Copy link
Author

FtpClientPool是标记为不弃用的;
正确使用连接池的方式是使用commons-pool2 提供的

GenericObjectPool<FTPClient> ftpClientPool=new GenericObjectPool<>(ftpClientFactory);

方法创建连接池

这个没有问题,我看了common-pool的实现是一致的。

@MarvinYu
Copy link
Author

MarvinYu commented Feb 14, 2019

@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)

@MarvinYu
Copy link
Author

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 处理下更适用于生产环境

@fortunelee
Copy link

six six six

@fortunelee
Copy link

写的太假了,自己写都比你那个强

@MarvinYu
Copy link
Author

写的太假了,自己写都比你那个强

写的挺好的,还需要考虑的点还有很多而已。这个目前还是一个待完善版本,类似于
http://commons.apache.org/proper/commons-pool/examples.html

@jayknoxqu
Copy link
Owner

非常感谢你提出了这么多问题,
FTP response 421 received这个问题我也检测出来了,感觉应该是保活的问题
GenericObjectPool确实是需要优化下

@MarvinYu
Copy link
Author

应该的,互相学习。应该是保活机制不完善,连接池没有对于池中连接进行有效性处理以及外部服务,网络抖动都可能导致这些失效。

@jayknoxqu
Copy link
Owner

写的太假了,自己写都比你那个强
@fortunelee
这个用于生产确实有问题,此项目主要是为了教学,让参与这个项目的人了解并熟悉连接池
,通过这个项目你应该掌握:
1.连接池的基本方法和调用流程,
2.Queue对列的基本用法.有界对列,无界对列等相关概念,
...

@jayknoxqu
Copy link
Owner

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());
    }
  }

可看下它具体是怎么来实现的,

@fortunelee
Copy link

@jayknoxqu 就你玩的花哨

@hackerys
Copy link

在检测到对象失效的时候,重新登录连接上ftp服务器,在放回对象池

@leyoliu1987
Copy link

试下这几个参数,每次获取一个连接,返还一个连接都测试 一下是否是可用的状态 ,如果不是会自动删除并重建,然后获取下一个
pool.setTestOnBorrow(true);
pool.setTestWhileIdle(true);
pool.setTestOnReturn(true);

@xchd
Copy link

xchd commented May 27, 2020

有更强的版本吗?从池中获取的client可能是断开的。导致程序异常。

@cookiespiggy
Copy link

@fortunelee 楼主写的这个挺好的,思想不错,pool2这个思想的确值得学习。但是FTP这个协议的确很复杂,数据口和控制口是两个socket,而且还要根据具体的FTP server端去配置client。兄台你这个头像挺骚气啊

@cookiespiggy
Copy link

cookiespiggy commented Jan 24, 2024 via email

Repository owner deleted a comment from mrpanday93 Feb 15, 2024
Repository owner deleted a comment from DylanZhu2021 Feb 23, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants