
本文详解如何在 jsch 中正确使用自定义 outputstream(如用于 google protocol buffers 封装),重点解决因未委托底层 socket 输出流导致连接冻结的问题,并提供可运行的代理流实现与关键注意事项。
本文详解如何在 jsch 中正确使用自定义 outputstream(如用于 google protocol buffers 封装),重点解决因未委托底层 socket 输出流导致连接冻结的问题,并提供可运行的代理流实现与关键注意事项。
JSch 本身不直接暴露 SSH 协议层的输入/输出流供用户替换,但允许通过 SocketFactory 自定义 Socket 的创建及配套的 InputStream/OutputStream。然而,关键误区在于:自定义 OutputStream 必须严格代理到底层 Socket 的原始输出流,而不能丢弃或中断其数据流向——否则 SSH 握手与后续通信将因数据无法抵达远端而卡死(表现为 session.connect() 阻塞)。
以下是一个安全、可扩展的 CustomOutputStream 实现,它采用组合模式封装真实输出流,并支持在转发前插入自定义序列化逻辑(如 Proto 封装):
public class ProtoWrappedOutputStream extends OutputStream {
private final OutputStream delegate; // 必须持有并委托给真实流
public ProtoWrappedOutputStream(Socket socket) throws IOException {
this(socket.getOutputStream()); // 从 Socket 获取原始流
}
public ProtoWrappedOutputStream(OutputStream delegate) {
this.delegate = Objects.requireNonNull(delegate, "delegate OutputStream cannot be null");
}
@Override
public void write(int b) throws IOException {
// 单字节写入 → 转为字节数组委托
delegate.write(b);
}
@Override
public void write(byte[] b, int off, int len) throws IOException {
if (b == null) throw new NullPointerException();
if (off < 0 || len < 0 || off + len > b.length) {
throw new IndexOutOfBoundsException();
}
if (len == 0) return;
// ✅ 在此处注入 Proto 封装逻辑(示例)
// JschProto.JschContents protoMsg = JschProto.JschContents.newBuilder()
// .setContent(ByteString.copyFrom(b, off, len))
// .setType("ssh-payload")
// .build();
// byte[] wrapped = protoMsg.toByteArray();
// delegate.write(wrapped);
// ⚠️ 当前为透传;若需封装,请注释掉下一行,启用上方 Proto 逻辑
delegate.write(b, off, len);
}
@Override
public void flush() throws IOException {
delegate.flush();
}
@Override
public void close() throws IOException {
delegate.close();
}
}在 SocketFactory 中使用时,需确保 getOutputStream() 返回该包装流,并传入真实的 socket.getOutputStream():
详细的 Three.js 3D 图形参考,涵盖场景设置、相机、几何体、材质、光照、动画、控制器、加载器、数学工具和调试。
session.setSocketFactory(new SocketFactory() {
@Override
public Socket createSocket(String host, int port) throws IOException {
return new Socket(host, port);
}
@Override
public InputStream getInputStream(Socket socket) throws IOException {
return socket.getInputStream(); // 保持原样
}
@Override
public OutputStream getOutputStream(Socket socket) throws IOException {
return new ProtoWrappedOutputStream(socket); // ✅ 正确传入 socket
}
});重要注意事项:
- ❌ 禁止在
CustomOutputStream中创建新Socket或忽略delegate直接空实现write()—— 这将切断 SSH 数据通路; - ✅ 所有
OutputStream标准方法(flush()、close())均需委托,否则资源泄漏或连接异常; - ? 若进行 Proto 封装,务必保证远端有对应解包逻辑,且封装格式需兼容 SSH 协议分帧(建议在应用层封装,而非破坏 SSH 二进制协议结构);
- ? 测试时先用透传模式验证连接正常,再逐步加入序列化逻辑,避免耦合问题干扰调试。
通过这种代理式封装,你既能无缝集成 JSch,又能灵活注入自定义传输语义,兼顾协议安全性与业务扩展性。

















