字节笔记本

2026年2月23日

DartSSH2:纯 Dart 编写的 SSH/SFTP 客户端库

DartSSH2 是一个使用纯 Dart 编写的 SSH 和 SFTP 客户端库,旨在提供功能丰富且易于使用的远程连接解决方案。该库支持 Dart VM 和 Flutter 环境,可用于构建跨平台的 SSH 客户端应用。

项目简介

DartSSH2 是 dartssh 的完全重写版本,由 TerminalStudio 团队开发维护。截至目前,该项目在 GitHub 上已获得 243+ stars,是一个成熟稳定的开源项目。

核心特性

  • 纯 Dart 实现:同时支持 Dart VM 和 Flutter 环境
  • SSH 会话管理:执行命令、交互式 Shell、环境变量设置、伪终端支持
  • 多种认证方式:支持密码认证、私钥认证和交互式认证
  • 端口转发:支持本地端口转发和远程端口转发
  • 完整 SFTP 支持:实现 SFTPv3 协议的所有操作,包括上传、下载、列表、链接、删除、重命名等

技术栈

  • Dart:核心编程语言
  • Flutter:支持移动端和桌面端应用开发
  • SSH-2.0 协议:兼容 OpenSSH 等主流 SSH 服务器
  • SFTPv3 协议:文件传输协议实现

安装指南

添加依赖

pubspec.yaml 文件中添加依赖:

yaml
dependencies:
  dartssh2: ^2.11.0

安装命令行工具

bash
# 安装 dartssh 命令行工具
dart pub global activate dartssh2_cli

# 使用 dartssh 作为常规 ssh 命令
dartssh user@example.com

# 执行远程命令
dartssh user@example.com ls -al

# 连接非标准端口
dartssh user@example.com:<port>

# 通过 SFTP 传输文件
dartsftp user@example.com

快速开始

连接到远程主机

dart
import 'package:dartssh2/dartssh2.dart';

void main() async {
  final client = SSHClient(
    await SSHSocket.connect('localhost', 22),
    username: '<username>',
    onPasswordRequest: () => '<password>',
  );
}

在远程主机上执行命令

dart
void main() async {
  final uptime = await client.run('uptime');
  print(utf8.decode(uptime));
}

启动交互式 Shell

dart
void main() async {
  final shell = await client.shell();
  stdout.addStream(shell.stdout);  // 监听标准输出
  stderr.addStream(shell.stderr);  // 监听标准错误
  stdin.cast<Uint8List>().listen(shell.write);  // 写入标准输入
  await shell.done;  // 等待 Shell 退出
  client.close();
}

使用示例

公钥认证

dart
void main() async {
  final client = SSHClient(
    socket,
    username: '<username>',
    identities: [
      // 单个私钥文件可能包含多个密钥
      ...SSHKeyPair.fromPem(await File('path/to/id_rsa').readAsString())
    ],
  );
}

加密 PEM 文件处理

dart
void main() async {
  // 检测私钥是否加密
  final encrypted = SSHKeyPair.isEncrypted(await File('path/to/id_rsa').readAsString());
  print(encrypted);

  // 如果私钥已加密,需要提供密码短语
  final keys = SSHKeyPair.fromPem('<pem text>', '<passphrase>');
  print(keys);
}

本地端口转发

dart
void main() async {
  final serverSocket = await ServerSocket.bind('localhost', 8080);
  await for (final socket in serverSocket) {
    final forward = await client.forwardLocal('httpbin.org', 80);
    forward.stream.cast<List<int>>().pipe(socket);
    socket.pipe(forward.sink);
  }
}

远程端口转发

dart
void main() async {
  final forward = await client.forwardRemote(port: 2222);
  if (forward == null) {
    print('Failed to forward remote port');
    return;
  }
  await for (final connection in forward.connections) {
    final socket = await Socket.connect('localhost', 22);
    connection.stream.cast<List<int>>().pipe(socket);
    socket.pipe(connection.sink);
  }
}

跳板机连接

dart
void main() async {
  final jumpServer = SSHClient(
    await SSHSocket.connect('<jump server>', 22),
    username: '...',
    onPasswordRequest: () => '...',
  );

  final client = SSHClient(
    await jumpServer.forwardLocal('<target server>', 22),
    username: '...',
    onPasswordRequest: () => '...',
  );

  print(utf8.decode(await client.run('hostname')));
}

SFTP 操作

列出远程目录

dart
void main() async {
  final sftp = await client.sftp();
  final items = await sftp.listdir('/');
  for (final item in items) {
    print(item.longname);
  }
}

读取远程文件

dart
void main() async {
  final sftp = await client.sftp();
  final file = await sftp.open('/etc/passwd');
  final content = await file.readBytes();
  print(latin1.decode(content));
}

文件上传

dart
void main() async {
  final sftp = await client.sftp();
  final file = await sftp.open('file.txt', mode: SftpFileOpenMode.create | SftpFileOpenMode.write);
  await file.write(File('local_file.txt').openRead().cast());
}

暂停和恢复上传

dart
void main() async {
  final uploader = await file.write(File('local_file.txt').openRead().cast());
  // ...
  await uploader.pause();
  // ...
  await uploader.resume();
  await uploader.done;
}

目录操作

dart
void main() async {
  final sftp = await client.sftp();
  await sftp.mkdir('/path/to/dir');
  await sftp.rmdir('/path/to/dir');
}

获取/设置文件属性

dart
void main() async {
  await sftp.stat('/path/to/file');
  await sftp.setStat(
    '/path/to/file',
    SftpFileAttrs(mode: SftpFileMode(userRead: true)),
  );
}

获取磁盘空间信息

dart
void main() async {
  final sftp = await client.sftp();
  final statvfs = await sftp.statvfs('/root');
  print('total: ${statvfs.blockSize * statvfs.totalBlocks}');
  print('free: ${statvfs.blockSize * statvfs.freeBlocks}');
}

基于 DartSSH2 构建的项目

  • ServerBox:Flutter 服务器管理应用
  • NoPorts:无需开放端口的 SSH 连接方案
  • DartShell:Dart SSH 终端工具

项目链接

分享: