SSHJ:exec 挂起或丢失数据

SSHJ: exec hangs or loses data

我已经使用 Trilead 和 Jsch 作为 Hg 的 SSH 客户端,现在我正在尝试使用 SSHJ,因为它似乎提供了更现代的密钥支持。草图代码显示为

SSHClient client = createClientAndAuthenticate();
Session session = client.startSession();
Command cmd = session.exec(command); // command usually is "hg -R /path/to/hg/repository serve --stdio"

startThreadToCopyInputStream(cmd.getOutputStream());

startThreadToCopyOutputStream(cmd.getInputStream());
startThreadToCopyOutputStream(cmd.getErrorStream());

cmd.join(); // here it hangs endlessly

startThreadToCopyInputStream方法将所有字节从本地Hg进程复制到cmd.getOutputStream(),然后完成输入流。但与 Trilead 和 JSch 相比,cmd.getInputStream()cmd.getErrorStream() 保持无限打开状态。

我现在将代码更改为:

SSHClient client = createClientAndAuthenticate();
Session session = client.startSession();
Command cmd = session.exec(command); // command usually is "hg -R /path/to/hg/repository serve --stdio"

startThreadToCopyInputStream(cmd.getOutputStream());

startThreadToCopyOutputStream(cmd.getInputStream());
startThreadToCopyOutputStream(cmd.getErrorStream());

waitUntilInputStreamIsClosed();
cmd.close();

这在 90% 的情况下都能正常工作,但有时 Hg 会抱怨服务器提前关闭了连接。我怎么知道什么时候可以调用 cmd.close() 因为服务器进程已经完成?

看起来这是 SSHJ 中的一个错误(参见 ticket 143)。解决方法是不直接使用 cmd.getOutputStream(),而是使用:

OutputStream cmdOutputStream = new FilterOutputStream(cmd.getOutputStream()) {
    @Override
    public void close() throws IOException {
        try {
            super.close();
        }
        finally {
            client.getTransport().write(new SSHPacket(Message.CHANNEL_EOF).putUInt32(session.getRecipient()));
        }
    }
};

在传递给 startThreadToCopyInputStream(cmdOutputStream); 之前。