【发布时间】:2017-05-28 13:45:47
【问题描述】:
我们在尝试为我们的应用程序实现 SftpConnections 池时遇到了一些问题。
我们目前使用SSHJ (Schmizz) 作为传输库,并面临一个我们根本无法在我们的开发环境中模拟的问题(但错误在生产中一直随机显示,有时在三天后,有时在 10 天后分钟)。
问题是,当尝试通过 SFTP 发送文件时,线程被锁定在来自 schmizz 的 TransportImpl 类的 init 方法中:
@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 对我们来说是 FALSE,所以首先客户端(我们)发送我们的标识,如日志中所示:
"客户身份字符串: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 方法的实现:
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 终止已建立的连接来模拟此错误,但一点运气都没有,所以任何帮助都会非常好感激不尽。
:)
【问题讨论】:
-
您是否尝试将“waitForServerIdent”标志设置为 true。您要连接的 SSH 服务器类型是什么?
-
你调查过线程转储吗?
-
Hiery Nomus :更改顺序没有区别,它是一个 SFTP 服务器。 : ) Vladislav : 线程转储在上述部分显示死锁:服务器没有响应,因此程序永远停止......这不是代码问题。
-
问题,你在哪里打电话给
SSHClient的setConnectTimeout? -
@Powerlord :是的,当客户端无法连接到某些目的地时,客户端会抛出连接超时异常,但在这种情况下不会。
标签: java sockets ssh sftp deadlock