本文开发环境为 Python 3.10 解释器、Paramiko 3.4.x 版本,适配华为 VRP V5 系统设备。
Paramiko 是 Python 生态中最底层的 SSH2 协议实现,纯 Python 编写,不依赖任何第三方二进制库,跨平台兼容性极强。但它不懂华为 VRP 系统的提示符规则,不会自动处理 ---- More ---- 分页,也不会帮你切换配置模式,所有交互逻辑都需要你自己用代码精确控制。Paramiko 的 SSHClient 实现了上下文管理器协议,配合 with 语句可以自动管理连接生命周期,避免 VTY 线路泄漏。这一篇就带你从零手搓一个能稳定对接华为设备的 Paramiko 封装。
基础连接与命令执行
Paramiko 建立 SSH 连接只需要 IP、用户名和密码(或密钥),但它不会自动识别设备提示符,也不会自动关闭分页。这意味着你发送 display version 后,必须自己判断输出何时结束、是否需要按空格翻页。下面这张表列出了最核心的四个方法,每个都标注了华为场景下的注意事项。
下面是使用 with 语句连接华为设备并执行命令的完整示例,每行都有注释说明数据流向:
import paramiko # 导入Paramiko核心模块
try:
# with语句创建SSH客户端,退出代码块时自动关闭连接
with paramiko.SSHClient() as client:
# 允许连接未知主机,生产环境建议加载known_hosts
# AutoAddPolicy自动接受并保存主机密钥,首次连接不会报错
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
# 建立SSH连接到华为VRP V5设备
# timeout控制TCP握手超时,banner_timeout控制等待SSH横幅超时
client.connect(
hostname="192.168.1.1", # 华为设备管理IP
port=22, # SSH端口
username="admin", # 登录用户名
password="Admin@123", # 登录密码
timeout=30, # TCP连接超时秒数
banner_timeout=30 # 等待SSH Banner超时秒数
)
# exec_command返回三元组:标准输入、标准输出、标准错误
# 注意:返回的是Channel对象,不是字符串
stdin, stdout, stderr = client.exec_command("display version")
# read()返回bytes类型,必须decode转为字符串
# 此处未处理分页,若输出超过一屏会被截断或阻塞
output = stdout.read().decode("utf-8")
error = stderr.read().decode("utf-8")
print(output)
if error:
print(f"错误信息: {error}")
except paramiko.AuthenticationException as e:
# 用户名或密码错误
print(f"认证失败: {e}")
except paramiko.SSHException as e:
# SSH协议层错误,如主机密钥验证失败
print(f"SSH异常: {e}")
except Exception as e:
# 兜底捕获网络不可达等其他异常
print(f"未知错误: {e}")
# with块结束,SSH连接已自动关闭,无需额外清理
这一节讲了用 with 语句管理 Paramiko 连接的基础流程,你会发现它比 Netmiko 多了不少"手工活",但也因此获得了完全的控制权。
交互式Shell与分页处理
exec_command 适合单条无交互命令,但华为 VRP V5 设备的 display 命令经常触发 ---- More ---- 分页,而且配置模式需要通过 system-view 进入、return 退出,这些都需要一个持久的交互式 Shell 会话。Paramiko 的 invoke_shell() 方法返回一个 Channel 对象,你可以像操作终端一样持续收发数据,但代价是所有提示符匹配和分页处理都得自己写。
下面是通过交互式 Shell 处理华为 VRP V5 分页和配置模式的完整示例:
import time # 用于等待设备响应
import paramiko # 导入Paramiko核心模块
def wait_for_prompt(channel, prompt, timeout=10):
"""循环读取直到匹配到期望提示符或超时"""
buffer = "" # 累积接收到的输出内容
start_time = time.time() # 记录开始时间用于超时判断
while True:
# 检查缓冲区是否有新数据到达
if channel.recv_ready():
# 每次最多读取4096字节,decode后追加到buffer
chunk = channel.recv(4096).decode("utf-8", errors="ignore")
buffer += chunk
# 检查是否匹配到目标提示符
if prompt in buffer:
return buffer
# 超时保护,防止设备无响应导致死循环
if time.time() - start_time > timeout:
raise TimeoutError(f"等待提示符'{prompt}'超时")
# 短暂休眠避免CPU空转
time.sleep(0.1)
try:
# with管理SSH客户端生命周期
with paramiko.SSHClient() as client:
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect(
hostname="192.168.1.1",
username="admin",
password="Admin@123",
timeout=30
)
# 打开交互式Shell,设置终端尺寸避免默认分页
# width=200让单行显示更多内容,减少分页触发概率
channel = client.invoke_shell(width=200, height=50)
# 等待登录后的用户视图提示符 <Huawei>
login_output = wait_for_prompt(channel, ">")
print(login_output)
# 关闭分页,VRP V5使用screen-length 0 temporary
# 发送命令必须带\n换行符,否则设备不会执行
channel.send("screen-length 0 temporary\n")
wait_for_prompt(channel, ">")
# 进入系统视图,VRP V5使用system-view命令
channel.send("system-view\n")
# 等待配置视图提示符 [Huawei]
config_output = wait_for_prompt(channel, "]")
print(config_output)
# 执行配置命令
channel.send("vlan 100\n")
wait_for_prompt(channel, "]")
# 退出配置模式回到用户视图
channel.send("return\n")
wait_for_prompt(channel, ">")
# 手动关闭Channel,with只负责关闭client
channel.close()
except Exception as e:
print(f"交互失败: {e}")
# with块结束,SSH连接自动释放
这一节讲了如何用 Paramiko 交互式 Shell 应对华为 VRP V5 的分页和模式切换,虽然代码量比 Netmiko 多,但你完全掌控了每一个交互细节。
注意事项与返回值处理
Paramiko 是把锋利的手术刀,用好了精准无比,用不好容易伤到自己。把这些注意事项记牢,能让你少踩很多弯路。
优先使用 with 语句管理连接:
with利用 Python 上下文管理器协议保证 SSHClient 一定被关闭,手动调用close()容易在异常分支中被跳过。但要注意with只管 Client 不管 Channel,交互式 Shell 的 Channel 必须手动关闭。VRP V5 分页命令是 screen-length 0 temporary:不要写成
terminal length 0(那是思科),也不要写成screen-length disable(部分新版本才支持)。这条命令必须在每条长输出命令前执行,或者在会话开始时统一执行一次。exec_command 与 invoke_shell 不要混用:同一个连接里先用
exec_command再开invoke_shell可能导致通道冲突。如果要做交互式操作,全程只用invoke_shell;如果只是跑几条简单查询,全程只用exec_command。recv 返回 bytes 必须 decode:Paramiko 所有收发都是字节流,忘记 decode 会导致字符串匹配永远失败。建议统一用
utf-8编码,加errors="ignore"防止个别乱码字符导致解码崩溃。提示符匹配要足够精确:VRP V5 用户视图是
<Hostname>,配置视图是[Hostname],接口视图是[Hostname-GigabitEthernet0/0/1]。用>匹配用户视图时注意排除配置视图中可能出现的>字符,建议用正则或更长的子串匹配。send 发送的命令必须以 \n 结尾:Paramiko 不会自动补换行符,漏掉
\n设备会一直等你输入,直到超时。这不是 bug,是底层协议的忠实还原。异常处理要分层:
AuthenticationException对应账号密码问题,SSHException对应协议层问题,socket.timeout对应网络问题。不要用一个笼统的except Exception吞掉所有异常,否则出了问题无法快速定位原因。并发连接要克制:华为 VRP V5 设备的 VTY 线路默认只有 5 条,同时开太多连接会把设备打满导致后续 Telnet/SSH 全部拒绝。建议使用线程池控制并发数,每个并发任务都应使用独立的
with块管理自己的连接生命周期。
Paramiko 给了你最底层的控制权,也意味着你要承担最多的责任。把基础打牢,把细节抠到位,你就能用它搞定那些 Netmiko 搞不定的奇葩设备和非标场景,当然大多数正常情况下,推荐用Netmiko库。