Python 终端自定义统计功能教程
1. 概述
本教程展示了如何使用Python编写一个简单的SSH客户端。该客户端连接到远程服务器,执行命令,并监听远程服务器的输出。本教程使用了paramiko库来处理SSH连接,使用了matplotlib来绘制图表,numpy处理数据,ctypes用于处理无符号64位整数。
2. 主要功能
- SSH连接 : 使用
paramiko库连接到远程服务器。 - 多线程监听 : 使用Python的
threading模块,允许同时监听远程服务器的输出和处理用户输入。 - 时间戳处理: 解析远程服务器输出中的特定时间戳,并计算发送和接收之间的时间差。
 - 数据可视化 : 使用
matplotlib生成并保存时间差的图表。 
3. 环境配置
- 
安装依赖库:
paramiko: 处理SSH连接。matplotlib: 用于绘制图表。numpy: 用于处理数据。
通过以下命令安装依赖:
bashpip 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函数来连接到指定的远程服务器。只需提供hostname、port、username和password,即可开始与服务器的交互。
6. 扩展与应用
- 你可以扩展此脚本以处理不同类型的命令和输出。
 - 可以将图表生成的逻辑进一步优化,例如增加数据的存储和分析功能。