我们在尝试为我们的应用程序实现SftpConnections池时遇到了一些麻烦.
我们目前正在使用SSHJ
(Schmizz)作为传输库,面临一个我们在开发环境中无法模拟的问题(但错误在生产中随机显示,有时在三天之后,有时仅在10分钟之后).
问题是,当尝试通过SFTP发送文件时,线程被锁定在init
schmizz' TransportImpl
类的方法中:
@Override public void init(String remoteHost, int remotePort, InputStream in, OutputStream out) throws TransportException { connInfo = new ConnInfo(remoteHost, remotePort, in, out); try { if (config.isWaitForServerIdentBeforeSendingClientIdent()) { receiveServerIdent(); sendClientIdent(); } else { sendClientIdent(); receiveServerIdent(); } log.info("Server identity string: {}", serverID); } catch (IOException e) { throw new TransportException(e); } reader.start(); }
isWaitForServerIdentBeforeSendingClientIdent对我们来说是假的,所以首先客户端(我们)发送我们的标识,如日志中所示:
" 客户身份字符串:blabla "
然后转向receiveServerIdent
:
private void receiveServerIdent() throws IOException { final Buffer.PlainBuffer buf = new Buffer.PlainBuffer(); while ((serverID = readIdentification(buf)).isEmpty()) { int b = connInfo.in.read(); if (b == -1) throw new TransportException("Server closed connection during identification exchange"); buf.putByte((byte) b); } }
线程永远不会得到控制权,因为服务器永远不会回复其身份.好像代码卡在这个While循环中.没有超时或SSH异常被抛出,我的客户端只是一直等待,线程陷入僵局.
这是readIdentification
方法的impl:
private String readIdentification(Buffer.PlainBuffer buffer) throws IOException { String ident = new IdentificationStringParser(buffer, loggerFactory).parseIdentificationString(); if (ident.isEmpty()) { return ident; } if (!ident.startsWith("SSH-2.0-") && !ident.startsWith("SSH-1.99-")) throw new TransportException(DisconnectReason.PROTOCOL_VERSION_NOT_SUPPORTED, "Server does not support SSHv2, identified as: " + ident); return ident; }
看起来像ConnectionInfo的输入流永远不会获取要读取的数据,就像服务器关闭了连接一样(即使如前所述,也没有抛出任何异常).
我试图通过使协商饱和来模拟这个错误,在连接时关闭套接字,使用conntrack在进行握手时杀死已建立的连接,但是根本没有运气,所以任何帮助都会非常感激.
:)