RemoteTerminal Python - SSH 远程终端工具

基于 PyQt5 + Paramiko 实现的 SSH 远程登录终端工具,包含服务器管理、多标签终端与远程文件浏览/下载。

在这里插入图片描述

环境要求

  • Python >= 3.9
  • Windows 10/11

功能特性

  • 服务器管理
    • 添加、编辑、删除服务器配置
    • 服务器分组管理
    • 配置信息持久化保存
  • SSH 连接
    • 密码认证
    • 密钥文件认证
    • 每次询问(ask)
    • 连接测试功能
  • 终端界面
    • 交互式 SSH 终端
    • 命令输入与执行
    • 实时输出显示
  • 远程文件浏览器
    • 浏览远程服务器文件系统
    • 查看文件和目录信息
    • 下载文件
  • 多标签页支持
    • 同时连接多个服务器
    • 标签页管理

安装依赖

pip install -r requirements.txt

快速开始(Windows)

  1. 安装依赖(见上)。
  2. 启动程序(二选一):
    • 方式 A:双击运行 run.bat
    • 方式 B:命令行运行:
python RemoteTerminal_python.py

使用方法

  • 添加服务器
    • 点击“添加服务器”按钮
    • 填写服务器信息(地址、端口、用户名、密码等)
    • 选择认证方式(密码/密钥/每次询问)
    • 点击“保存”
  • 连接服务器
    • 双击服务器列表中的服务器
    • 或右键点击选择“连接”
  • 使用终端
    • 在终端标签页中输入命令
    • 按 Enter 或点击“发送”按钮执行命令
  • 浏览文件
    • 在左侧文件浏览器中浏览远程文件系统
    • 双击目录进入
    • 右键文件可下载

SSH 核心代码说明

  • 连接线程:SSHConnection

    • 继承自 QThread,在独立线程中维护与远程主机的 SSH 会话,避免阻塞 GUI。
    • run() 中使用 paramiko.SSHClient 创建连接,根据是否配置密钥文件选择:
      • 密钥登录:client.connect(..., key_filename=key_file, timeout=10)
      • 密码登录:client.connect(..., password=password, timeout=10)
    • 通过 client.invoke_shell(term='xterm-256color') 创建交互式 SSH shell 通道 channel
    • 持续轮询 channel.recv_ready(),有数据时调用 channel.recv(4096) 并解码为字符串,通过 output_received 信号异步发送给界面。
    • 出现异常时,通过 error_occurred 信号上报错误,在 finally 中统一发出 connection_closed 信号,便于界面做收尾处理。
  • 命令发送与关闭

    • send_command(command) 会在通道仍然可用时执行 self.channel.send(command),通常由终端输入框在用户按下 Enter 时调用(会附带换行符)。
    • close() 方法将 running 置为 False,并关闭底层 channelclient,让线程循环自然退出。
  • 连接测试

    • 在服务器配置对话框中,test_connection() 会临时创建一个 paramiko.SSHClient,用与实际连接相同的参数执行一次 connect / close
    • 成功则弹出“连接测试成功”提示,失败则捕获异常并展示错误信息,便于提前发现账号或网络问题。

示例核心代码:

import os
import time

import paramiko
from PyQt5.QtCore import QThread, pyqtSignal


class SSHConnection(QThread):
    """SSH 连接线程"""
    output_received = pyqtSignal(str)
    error_occurred = pyqtSignal(str)
    connection_closed = pyqtSignal()

    def __init__(self, host, port, username, password=None, key_file=None):
        super().__init__()
        self.host = host
        self.port = port
        self.username = username
        self.password = password
        self.key_file = key_file
        self.client = None
        self.channel = None
        self.running = False

    def run(self):
        try:
            self.client = paramiko.SSHClient()
            self.client.set_missing_host_key_policy(paramiko.AutoAddPolicy())

            # 连接服务器(密钥优先,其次密码)
            if self.key_file and os.path.exists(self.key_file):
                self.client.connect(
                    hostname=self.host,
                    port=self.port,
                    username=self.username,
                    key_filename=self.key_file,
                    timeout=10,
                )
            else:
                self.client.connect(
                    hostname=self.host,
                    port=self.port,
                    username=self.username,
                    password=self.password,
                    timeout=10,
                )

            # 创建交互式 shell
            self.channel = self.client.invoke_shell(term="xterm-256color")
            self.running = True

            # 持续读取远程输出
            while self.running:
                if self.channel.recv_ready():
                    data = self.channel.recv(4096).decode("utf-8", errors="ignore")
                    if data:
                        self.output_received.emit(data)
                elif self.channel.exit_status_ready():
                    break
                time.sleep(0.1)

        except Exception as e:
            self.error_occurred.emit(str(e))
        finally:
            self.connection_closed.emit()

    def send_command(self, command: str):
        """发送命令到远程 shell"""
        if self.channel and self.running:
            self.channel.send(command)

    def close(self):
        """关闭连接"""
        self.running = False
        if self.channel:
            self.channel.close()
        if self.client:
            self.client.close()

配置说明(servers.json)

服务器配置保存在 servers.json 文件中,包含以下字段:

  • name: 服务器名称
  • host: 服务器地址
  • port: SSH 端口(默认 22)
  • username: 登录用户名
  • password: 登录密码(密码认证时)
  • key_file: SSH 密钥文件路径(密钥认证时)
  • group: 服务器分组
  • auth_method: 认证方式(password / key / ask
  • notes: 备注信息

安全提示:

  • servers.json 可能包含密码等敏感信息,建议仅在本机保存,不要随意分享/上传。
  • 当前实现会在首次连接时 自动接受主机密钥(Paramiko AutoAddPolicy)。在生产环境建议改为校验指纹/已知主机列表,避免中间人风险。
  • 若使用密钥文件,建议使用 绝对路径,并确保密钥权限设置合理。

打包(PyInstaller)

推荐直接使用仓库内的 RemoteTerminalPython.spec

pyinstaller --noconfirm --clean RemoteTerminalPython.spec

如果要用命令行参数方式(Windows 示例,注意 --add-data 分隔符为 ;):

pyinstaller --noconfirm --clean --windowed --onedir --name "RemoteTerminalPython" --add-data "servers.json;." RemoteTerminal_python.py

依赖库

  • PyQt5: GUI 界面框架
  • paramiko: SSH 客户端库

许可证

MIT License

GitHub 项目地址

CarryingFish

Logo

小龙虾开发者社区是 CSDN 旗下专注 OpenClaw 生态的官方阵地,聚焦技能开发、插件实践与部署教程,为开发者提供可直接落地的方案、工具与交流平台,助力高效构建与落地 AI 应用

更多推荐