You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

移动端SSHD服务器向JSch客户端传文件遇连接重置问题求助

问题:安卓模拟器JSch客户端连接手机SSHD服务器时出现连接重置

手机上运行的SSHD服务器无报错,但安卓模拟器里的JSch客户端尝试从手机内部存储下载文件时,抛出Connection reset错误。已添加网络权限和相关依赖,问题仍未解决。


客户端代码

public void startClient(){
   String localFile = "/data/user/0/com.open.jsch/databases/au.au_1";
    String remoteFile = "/data/user/0/com.open.androidsshd/databases/au.au_1";
    Session jschSession = null;
    try {
    JSch jsch = new JSch();
    jsch.setKnownHosts("/home/mkyong/.ssh/known_hosts");
    jschSession = jsch.getSession(USERNAME, REMOTE_HOST, REMOTE_PORT);
    // authenticate using private key
    // jsch.addIdentity("/home/mkyong/.ssh/id_rsa");
    // authenticate using password
    jschSession.setPassword(PASSWORD);
    //Missing code
    java.util.Properties config = new java.util.Properties();
    config.put("StrictHostKeyChecking", "no");
    jschSession.setConfig(config);
    //
    System.out.println("Establishing connection");
    // 10 seconds session timeout
    jschSession.connect(SESSION_TIMEOUT);
    Channel sftp = jschSession.openChannel("sftp");
    // 5 seconds timeout
    sftp.connect(CHANNEL_TIMEOUT);
    ChannelSftp channelSftp = (ChannelSftp) sftp;
    // transfer file from local to remote server
    //channelSftp.put(localFile, remoteFile);
    // download file from remote server to local
    channelSftp.get(remoteFile, localFile);
    System.out.println("got the file");
    channelSftp.exit();
    } catch (JSchException | SftpException e) {
    e.printStackTrace();
    } finally {
    if (jschSession != null) {
        jschSession.disconnect();
    }
    }
   }

客户端错误日志

2022-10-30 21:55:59.228 15159-15202/com.allah.jsch W/System.err: com.jcraft.jsch.JSchException:     Session.connect: java.net.SocketException: Connection reset
2022-10-30 21:55:59.228 15159-15202/com.allah.jsch W/System.err:     at  com.jcraft.jsch.Session.connect(Session.java:565)
2022-10-30 21:55:59.228 15159-15202/com.allah.jsch W/System.err:     at com.allah.jsch.Client.startClient(Client.java:71)
2022-10-30 21:55:59.228 15159-15202/com.allah.jsch W/System.err:     at com.allah.jsch.MainActivity$2.run(MainActivity.java:78)
2022-10-30 21:55:59.229 15159-15202/com.allah.jsch W/System.err:     at java.lang.Thread.run(Thread.java:764)

服务器代码

int port = 8888;
SshServer sshd = SshServer.setUpDefaultServer();
sshd.setPort(port);
sshd.setKeyPairProvider(new SimpleGeneratorHostKeyProvider(
    "src/test/resources/hostkey.ser"));
sshd.setSubsystemFactories(Arrays
    .<NamedFactory<Command>>asList(new SftpSubsystem.Factory()));
sshd.setCommandFactory(new ScpCommandFactory());
sshd.setShellFactory(new EchoShellFactory()); // necessary if you want to type commands over ssh
sshd.setPasswordAuthenticator(new PasswordAuthenticator() {
@Override
public boolean authenticate(String u, String p, ServerSession s) {
    return ("sftptest".equals(u) && "sftptest".equals(p));
}
});
try {
sshd.start();
} catch (IOException e) {
e.printStackTrace();
}

权限配置

<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />

客户端Gradle依赖

// https://mvnrepository.com/artifact/org.apache.sshd/sshd-core
implementation group: 'org.apache.sshd', name: 'sshd-core', version: '0.6.0'
// https://mvnrepository.com/artifact/org.slf4j/slf4j-simple
testImplementation group: 'org.slf4j', name: 'slf4j-simple', version: '1.6.2'
// https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk16
implementation group: 'org.bouncycastle', name: 'bcprov-jdk16', version: '1.46'
implementation files('libs\\jsch-0.1.55.jar')

可行解决方案

1. 修正模拟器与真机的网络连通性

安卓模拟器无法直接用localhost访问物理真机,需:

  • 将客户端REMOTE_HOST设置为真机的局域网IP(可通过手机WiFi设置查看)
  • 确保真机和模拟器连接同一WiFi网络
  • 若使用Android Studio模拟器,物理真机需用自身局域网IP,而非10.0.2.2(该地址仅映射到模拟器宿主机)

2. 修复服务器HostKey存储路径

服务器代码中src/test/resources/hostkey.ser是桌面环境路径,安卓真机无法识别,需改为应用内部存储路径:

// 获取应用内部存储目录
String hostKeyPath = getFilesDir().getAbsolutePath() + "/hostkey.ser";
sshd.setKeyPairProvider(new SimpleGeneratorHostKeyProvider(hostKeyPath));

HostKey生成失败会直接导致SSH握手中断,触发连接重置。

3. 解决依赖冲突

客户端同时引入sshd-core和JSch两个SSH客户端实现,存在版本冲突,移除sshd-core相关依赖:

// 移除冲突依赖
// implementation group: 'org.apache.sshd', name: 'sshd-core', version: '0.6.0'
// testImplementation group: 'org.slf4j', name: 'slf4j-simple', version: '1.6.2'

// 保留必要依赖
implementation group: 'org.bouncycastle', name: 'bcprov-jdk16', version: '1.46'
implementation files('libs\\jsch-0.1.55.jar')

4. 移除客户端无效的KnownHosts配置

客户端代码中/home/mkyong/.ssh/known_hosts是Linux桌面路径,安卓模拟器不存在,直接注释:

// jsch.setKnownHosts("/home/mkyong/.ssh/known_hosts");

已设置StrictHostKeyChecking=no,无需该文件。

5. 验证服务器端口可用性

  • 在真机上用netstat命令检查8888端口是否被占用
  • 关闭真机防火墙(若有),确保允许8888端口的TCP连接
  • 用电脑SSH工具连接真机IP+8888端口,验证服务器是否正常响应

6. 延长超时时间并增加调试日志

延长客户端连接超时,避免网络延迟导致重置:

// 会话超时改为30秒
jschSession.connect(30000);
Channel sftp = jschSession.openChannel("sftp");
// 通道超时改为10秒
sftp.connect(10000);

服务器添加会话监听日志,确认是否收到连接请求:

sshd.setSessionListener(new SessionListener() {
    @Override
    public void sessionCreated(ServerSession session) {
        Log.d("SSHD", "收到新连接:" + session.getIoSession().getRemoteAddress());
    }

    @Override
    public void sessionEvent(ServerSession session, Event event) {}

    @Override
    public void sessionClosed(ServerSession session) {}
});

内容的提问来源于stack exchange,提问作者CodeBlack

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 00:05:24