Python基础 -- 使用Python实现ssh终端并实现数据处理与统计功能

Python 终端自定义统计功能教程

1. 概述

本教程展示了如何使用Python编写一个简单的SSH客户端。该客户端连接到远程服务器,执行命令,并监听远程服务器的输出。本教程使用了paramiko库来处理SSH连接,使用了matplotlib来绘制图表,numpy处理数据,ctypes用于处理无符号64位整数。

2. 主要功能

  • SSH连接 : 使用paramiko库连接到远程服务器。
  • 多线程监听 : 使用Python的threading模块,允许同时监听远程服务器的输出和处理用户输入。
  • 时间戳处理: 解析远程服务器输出中的特定时间戳,并计算发送和接收之间的时间差。
  • 数据可视化 : 使用matplotlib生成并保存时间差的图表。

3. 环境配置

  • 安装依赖库:

    • paramiko: 处理SSH连接。
    • matplotlib: 用于绘制图表。
    • numpy: 用于处理数据。

    通过以下命令安装依赖:

    bash 复制代码
    pip install paramiko matplotlib numpy

4. 代码解释

python 复制代码
import paramiko
import threading
import matplotlib.pyplot as plt
import ctypes
import numpy as np
from datetime import datetime

# 全局列表,用于存储接收到的时间戳
ts_rpmsg_resp = []
ts_rpmsg_send = []

def ssh_connect_and_execute(hostname, port, username, password):
    """
    连接到远程服务器,打开一个交互式Shell会话,并处理远程输出。

    参数:
        hostname (str): 远程服务器的IP地址或主机名。
        port (int): SSH连接使用的端口号。
        username (str): SSH登录的用户名。
        password (str): SSH登录的密码。
    """
    # 创建SSH客户端实例
    ssh = paramiko.SSHClient()
    
    # 将未知主机自动添加到known_hosts文件中
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

    try:
        # 尝试连接到远程服务器
        ssh.connect(hostname, port, username, password)
        
        # 打开一个交互式的Shell会话,允许执行远程命令
        channel = ssh.invoke_shell()

        def listen_to_remote_output():
            """
            监听远程服务器的输出,处理并提取特定的时间戳数据。
            """
            buffer = ""
            while True:
                # 检查是否有数据可读
                if channel.recv_ready():
                    data = channel.recv(1024).decode('utf-8')  # 接收数据并解码
                    buffer += data
                    
                    # 按行处理接收到的数据
                    while "\n" in buffer:
                        line, buffer = buffer.split("\n", 1)
                        print(line)  # 输出接收到的每行数据
                        
                        # 检测并处理发送时间戳
                        if "set_light_state_rpmsg:366 rpmsg_send start at:" in line:
                            timestamp_str = line.split(':')[-1].strip()
                            timestamp = ctypes.c_uint64(int(timestamp_str)).value
                            ts_rpmsg_send.append(timestamp)
                            print("========== send ===========\n")
                        
                        # 检测并处理接收时间戳
                        if "rpmsg_recv:64 len:32 at:" in line:
                            timestamp_str = line.split(':')[-1].strip()
                            timestamp = ctypes.c_uint64(int(timestamp_str)).value
                            ts_rpmsg_resp.append(timestamp)
                            print("========== resp ===========\n")
                        
                        # 如果接收到超过100个时间戳,绘制时间差图表
                        if len(ts_rpmsg_resp) > 100:
                            array1 = np.array(ts_rpmsg_resp, dtype=np.uint64)
                            array2 = np.array(ts_rpmsg_send, dtype=np.uint64)
                            differences = array1 - array2
                            
                            # 绘制时间差的折线图
                            plt.plot(range(len(differences)), differences, marker='o')
                            plt.xlabel('Index')
                            plt.ylabel('Difference')
                            plt.title('Difference between send and receive timestamps')
                            plt.grid(True)
                            
                            # 保存图像为PNG文件
                            ts_file_name = datetime.now().strftime("%Y%m%d_%H%M%S")
                            filename = f"difference_plot_{ts_file_name}.png"
                            plt.savefig(filename)
                            
                            # 清空时间戳列表,为下一批数据做准备
                            ts_rpmsg_resp.clear()
                            ts_rpmsg_send.clear()

        # 启动一个新线程来监听远程服务器的输出
        threading.Thread(target=listen_to_remote_output, daemon=True).start()

        # 主线程循环,等待用户输入命令
        while True:
            user_input = input("Enter command: ")  # 获取用户输入
            if user_input:  # 如果输入不为空
                channel.send(user_input + "\n")  # 发送命令到远程服务器
                print(f"Sent: {user_input}")

    except Exception as e:
        print(f"SSH connection failed: {e}")  # 捕获并打印任何异常
    finally:
        ssh.close()  # 关闭SSH连接

# 使用示例:使用上述函数连接到指定的SSH服务器
hostname = "192.168.1.26"
port = 22  # SSH默认端口
username = "root"
password = ""

ssh_connect_and_execute(hostname, port, username, password)

5. 使用示例

最后展示了如何调用ssh_connect_and_execute函数来连接到指定的远程服务器。只需提供hostnameportusernamepassword,即可开始与服务器的交互。

6. 扩展与应用

  • 你可以扩展此脚本以处理不同类型的命令和输出。
  • 可以将图表生成的逻辑进一步优化,例如增加数据的存储和分析功能。
相关推荐
上单带刀不带妹1 小时前
手写 Vue 中虚拟 DOM 到真实 DOM 的完整过程
开发语言·前端·javascript·vue.js·前端框架
im_AMBER1 小时前
学习日志05 python
python·学习
大虫小呓1 小时前
Python 处理 Excel 数据 pandas 和 openpyxl 哪家强?
python·pandas
哪 吒1 小时前
2025B卷 - 华为OD机试七日集训第5期 - 按算法分类,由易到难,循序渐进,玩转OD(Python/JS/C/C++)
python·算法·华为od·华为od机试·2025b卷
-凌凌漆-1 小时前
【Qt】QStringLiteral 介绍
开发语言·qt
程序员爱钓鱼1 小时前
Go语言项目工程化 — 常见开发工具与 CI/CD 支持
开发语言·后端·golang·gin
军训猫猫头2 小时前
1.如何对多个控件进行高效的绑定 C#例子 WPF例子
开发语言·算法·c#·.net
真的想上岸啊2 小时前
学习C++、QT---18(C++ 记事本项目的stylesheet)
开发语言·c++·学习
明天好,会的2 小时前
跨平台ZeroMQ:在Rust中使用zmq库的完整指南
开发语言·后端·rust
摸爬滚打李上进2 小时前
重生学AI第十六集:线性层nn.Linear
人工智能·pytorch·python·神经网络·机器学习