解析Linux top 命令输出并生成动态图表

文章目录

    • 0. 引言
    • 1. 原理
    • 2. 功能
    • 3. 程序架构
        • 流程图
        • 结构图
    • 4. 数据解析模块
    • 5. 图表绘制模块
    • 6. 主程序入口
    • 7. 使用方法
    • 8. 总结
    • 9. 附录完整代码

0. 引言

在性能调优和系统监控中,top 命令是一种重要工具,提供了实时的系统状态信息,如 CPU 使用率、内存使用情况和进程状态。然而,仅凭命令行输出可能无法满足复杂的分析需求。
本文将介绍如何解析 top 命令的输出,并利用 Python 生成动态图表,以更直观地展示系统性能数据。

1. 原理

解析 top 命令输出的核心在于文本处理。由于不同版本和配置的 top 命令可能输出格式略有不同,因此需要编写灵活的解析器来处理这些差异。最终,解析出的数据将通过 pandas 库进行处理,并使用 matplotlib 生成动态图表。

2. 功能

  • 解析不同格式的 top 输出

    • 自动识别并处理 KiB MemGiB Mem 两种格式的内存信息。
    • 提取每个进程的 PID、用户、CPU 使用率、内存使用率、运行时间和命令信息。
  • 生成动态图表

    • 绘制系统总体内存使用情况的动态曲线(总内存、空闲内存、使用内存、缓存/缓冲区内存)。
    • 绘制指定进程或线程的 CPU 和内存使用情况的动态曲线。
    • 支持通过命令行参数配置显示选项,例如是否显示所有线程的详细信息。
      请添加图片描述

3. 程序架构

本程序主要分为以下几个模块:

  • 数据解析模块:负责解析 top 命令的输出文本,并将提取的数据存储到 pandas 的数据帧中。

  • 图表绘制模块:基于解析得到的数据帧,使用 matplotlib 生成动态图表。

  • 主程序入口:处理命令行参数,调用数据解析模块和图表绘制模块完成数据处理和图表生成的流程。

流程图

流程图将展示数据解析模块、图表绘制模块和主程序入口之间的交互过程。以下是流程图的示意:

主程序入口
解析 `top` 输出文件
生成 `pandas` 数据帧
调用图表绘制模块
生成动态图表
显示或保存图表
结束
结构图

结构图将展示程序的整体架构,包括数据解析模块、图表绘制模块和主程序入口的功能组成及其关系。以下是结构图的示意:

主程序入口
解析 `top` 输出文件
图表绘制模块
处理命令行参数
解析 `top` 输出文本
生成 `pandas` 数据帧
绘制内存使用动态曲线
绘制进程线程动态曲线
时间轴处理
内存使用情况处理
进程线程动态曲线处理
绘制动态图表
存储信息

4. 数据解析模块

数据解析模块的主要任务是读取 top 命令的输出文件,识别其格式并提取出需要的性能指标和进程信息。以下是核心代码片段的部分实现:

# 数据解析模块核心代码示例
import pandas as pd
import re

def parse_top_output(file_path):
    columns = ['timestamp', 'total_mem', 'free_mem', 'used_mem', 'buff_cache_mem', 'pid', 'user', 'cpu', 'mem', 'time', 'command']
    data = {col: [] for col in columns}

    with open(file_path, 'r') as file:
        lines = file.readlines()

    timestamp = None
    format_type = None
    for line in lines:
        if line.startswith('top -'):
            timestamp = re.search(r'top - (\d+:\d+:\d+)', line).group(1)
        elif 'KiB Mem :' in line or 'GiB Mem :' in line:
            format_type = 'format1' if 'KiB Mem :' in line else 'format2'
            mem_info = re.findall(r'[\d\.]+', line)
            if format_type == 'format1':
                data['total_mem'].append(int(mem_info[0]))
                data['free_mem'].append(int(mem_info[1]))
                data['used_mem'].append(int(mem_info[2]))
                data['buff_cache_mem'].append(int(mem_info[3]))
            else:
                total_mem_gb = float(mem_info[0])
                data['total_mem'].append(total_mem_gb * 1024 * 1024)
                data['free_mem'].append(None)
                data['used_mem'].append(None)
                data['buff_cache_mem'].append(None)
            data['timestamp'].append(timestamp)
            data['pid'].append(None)
            data['user'].append(None)
            data['cpu'].append(None)
            data['mem'].append(None)
            data['time'].append(None)
            data['command'].append(None)
        elif re.match(r'\s*\d+', line) or re.match(r'\s*\d+\s+\w+', line):
            if format_type == 'format1':
                proc_info = re.split(r'\s+', line.strip(), maxsplit=11)
                data['pid'].append(int(proc_info[0]))
                data['user'].append(proc_info[1])
                data['cpu'].append(float(proc_info[8]))
                data['mem'].append(float(proc_info[9]))
                data['time'].append(proc_info[10])
                data['command'].append(proc_info[11] if len(proc_info) > 11 else "")
            elif format_type == 'format2':
                proc_info = re.split(r'\s+', line.strip(), maxsplit=10)
                data['pid'].append(int(proc_info[0]))
                data['user'].append(proc_info[1])
                try:
                    cpu_value = float(proc_info[5].strip('%')) if '%' in proc_info[5] else float(proc_info[5])
                    mem_value = float(proc_info[6].strip('%')) if '%' in proc_info[6] else float(proc_info[6])
                except ValueError:
                    cpu_value = 0.0
                    mem_value = 0.0
                data['cpu'].append(cpu_value)
                data['mem'].append(mem_value)
                data['time'].append(proc_info[7])
                data['command'].append(proc_info[9] if len(proc_info) > 9 else "")
            data['timestamp'].append(timestamp)
            data['total_mem'].append(None)
            data['free_mem'].append(None)
            data['used_mem'].append(None)
            data['buff_cache_mem'].append(None)
        else:
            data['timestamp'].append(timestamp)
            for key in data:
                if key not in ['timestamp']:
                    data[key].append(None)

    df = pd.DataFrame(data)
    df['timestamp'] = pd.to_datetime(df['timestamp'], format='%H:%M:%S')
    df['relative_time'] = (df['timestamp'] - df['timestamp'].min()).dt.total_seconds()
    return df

5. 图表绘制模块

图表绘制模块利用 matplotlib 库生成动态图表,以下是绘制内存使用动态曲线和进程线程动态曲线的核心代码片段:

# 图表绘制模块核心代码示例
import matplotlib.pyplot as plt
from matplotlib.ticker import MaxNLocator, AutoLocator

def plot_memory_usage(ax, df, process_name=None):
    if 'relative_time' not in df.columns:
        print("relative_time column is missing in the dataframe")
        return
    
    memory_cols = ['total_mem', 'free_mem', 'used_mem', 'buff_cache_mem']
    df_memory = df.dropna(subset=memory_cols).drop_duplicates(subset=['relative_time'])

    max_memory = df_memory[memory_cols].max().max()  # 获取内存使用的最大值

    for col in memory_cols:
        ax.plot(df_memory['relative_time'], df_memory[col], label=col.replace('_', ' ').title())

    ax.set_xlabel('Time (seconds)')
    ax.set_ylabel('Memory (KiB)')
    ax.set_ylim(0, max_memory * 1.1 if max_memory > 0 else 1)
    ax.set_title('Memory Usage Over Time')
    if process_name:
        ax.text(0.5, 0.5, process_name, transform=ax.transAxes, fontsize=20, ha='center', va='center', alpha=0.7, color='black')
    ax.legend()
    ax.grid(True)
    ax.xaxis.set_major_locator(AutoLocator())
    ax.yaxis.set_major_locator(MaxNLocator(integer=True))

    return ax

def plot_process_threads(ax, df, processes, show_threads, metric='cpu'):
    for process in processes:
        df_process = df[df['command'].str.contains(process, na=False)]
        if show_threads:
            unique_pids = df_process['pid'].unique()
            for pid in unique_pids:
                df_pid = df_process[df_process['pid'] == pid]
                ax.plot(df_pid['relative_time'], df_pid[metric], label=f'{process} {metric.upper()} (PID {pid})')
        else:
            df_process_grouped = df_process.groupby('relative_time').agg({metric: 'sum'}).reset_index()
            ax.plot(df_process_grouped['relative_time'], df_process_grouped[metric], label=f'{process} (Total {metric.upper()})')
    ax.set_xlabel('

Time (seconds)')
    ax.set_ylabel(f'{metric.upper()} Usage')
    ax.set_title(f'{metric.upper()} Usage of Processes and Threads Over Time')
    ax.legend()
    ax.grid(True)
    ax.xaxis.set_major_locator(AutoLocator())
    ax.yaxis.set_major_locator(MaxNLocator(integer=True))

    return ax

6. 主程序入口

主程序入口负责处理命令行参数,并调用数据解析和图表绘制模块完成数据处理和图表生成的流程。以下是主程序入口的核心代码片段:

# 主程序入口核心代码示例
import argparse

def main(file_path, processes, show_threads, save_fig=False):
    df = parse_top_output(file_path)
    plot_all(df, processes, show_threads, save_fig)

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description='Parse and plot top command output.')
    parser.add_argument('--file', type=str, required=True, help='Path to the top output file')
    parser.add_argument('--process', type=str, nargs='+', required=True, help='List of processes to plot')
    parser.add_argument('--show_threads', action='store_true', help='Show CPU and memory for all threads within the process')
    parser.add_argument('--save_fig', action='store_true', help='Save the generated plots as PNG images')

    args = parser.parse_args()
    main(args.file, args.process, args.show_threads, args.save_fig)

7. 使用方法

  1. 准备 top 输出文件

    • 运行 top 命令并将输出保存到文件中,例如 top -b -n 1 > topdump.txt
  2. 运行解析和绘图脚本

    • 使用以下命令解析 top 输出文件并生成动态图表:

      python top_parser.py --file topdump.txt --process <process_name> --show_threads --save_fig
      
    • 参数说明:

      • --file:指定 top 输出文件的路径。
      • --process:指定要绘制的进程名称。
      • --show_threads:可选参数,显示进程内所有线程的详细信息。
      • --save_fig:可选参数,保存生成的图表为 PNG 图像文件。

8. 总结

通过本文介绍的方法,可以有效解析 top 命令输出并生成动态图表,帮助用户更直观地分析系统性能数据。该方法不仅支持不同格式的 top 输出,还能够灵活配置,满足各种监控需求。

9. 附录完整代码

import pandas as pd
import matplotlib.pyplot as plt
import re
import argparse
from matplotlib.ticker import MaxNLocator, AutoLocator

# 解析top命令输出
def parse_top_output(file_path):
    columns = ['timestamp', 'total_mem', 'free_mem', 'used_mem', 'buff_cache_mem', 'pid', 'user', 'cpu', 'mem', 'time', 'command']
    data = {col: [] for col in columns}

    with open(file_path, 'r') as file:
        lines = file.readlines()

    timestamp = None
    format_type = None
    for line in lines:
        if line.startswith('top -'):
            timestamp = re.search(r'top - (\d+:\d+:\d+)', line).group(1)
        elif 'KiB Mem :' in line or 'GiB Mem :' in line:
            format_type = 'format1' if 'KiB Mem :' in line else 'format2'
            mem_info = re.findall(r'[\d\.]+', line)
            if format_type == 'format1':
                data['total_mem'].append(int(mem_info[0]))
                data['free_mem'].append(int(mem_info[1]))
                data['used_mem'].append(int(mem_info[2]))
                data['buff_cache_mem'].append(int(mem_info[3]))
            else:
                total_mem_gb = float(mem_info[0])
                data['total_mem'].append(total_mem_gb * 1024 * 1024)
                data['free_mem'].append(None)
                data['used_mem'].append(None)
                data['buff_cache_mem'].append(None)
            data['timestamp'].append(timestamp)
            data['pid'].append(None)
            data['user'].append(None)
            data['cpu'].append(None)
            data['mem'].append(None)
            data['time'].append(None)
            data['command'].append(None)
        elif re.match(r'\s*\d+', line) or re.match(r'\s*\d+\s+\w+', line):
            if format_type == 'format1':
                proc_info = re.split(r'\s+', line.strip(), maxsplit=11)
                data['pid'].append(int(proc_info[0]))
                data['user'].append(proc_info[1])
                data['cpu'].append(float(proc_info[8]))
                data['mem'].append(float(proc_info[9]))
                data['time'].append(proc_info[10])
                data['command'].append(proc_info[11] if len(proc_info) > 11 else "")
            elif format_type == 'format2':
                proc_info = re.split(r'\s+', line.strip(), maxsplit=10)
                data['pid'].append(int(proc_info[0]))
                data['user'].append(proc_info[1])
                try:
                    cpu_value = float(proc_info[5].strip('%')) if '%' in proc_info[5] else float(proc_info[5])
                    mem_value = float(proc_info[6].strip('%')) if '%' in proc_info[6] else float(proc_info[6])
                except ValueError:
                    cpu_value = 0.0
                    mem_value = 0.0
                data['cpu'].append(cpu_value)
                data['mem'].append(mem_value)
                data['time'].append(proc_info[7])
                data['command'].append(proc_info[9] if len(proc_info) > 9 else "")
            data['timestamp'].append(timestamp)
            data['total_mem'].append(None)
            data['free_mem'].append(None)
            data['used_mem'].append(None)
            data['buff_cache_mem'].append(None)
        else:
            data['timestamp'].append(timestamp)
            for key in data:
                if key not in ['timestamp']:
                    data[key].append(None)

    df = pd.DataFrame(data)
    df['timestamp'] = pd.to_datetime(df['timestamp'], format='%H:%M:%S')
    df['relative_time'] = (df['timestamp'] - df['timestamp'].min()).dt.total_seconds()
    return df

# 将时间戳转换为秒数
def convert_timestamp_to_seconds(timestamp):
    h, m, s = map(int, timestamp.split(':'))
    return h * 3600 + m * 60 + s

# 绘制内存动态曲线
def plot_memory_usage(ax, df, process_name=None):
    if 'relative_time' not in df.columns:
        print("relative_time column is missing in the dataframe")
        return

    memory_cols = ['total_mem', 'free_mem', 'used_mem', 'buff_cache_mem']
    df_memory = df.dropna(subset=memory_cols).drop_duplicates(subset=['relative_time'])

    max_memory = df_memory[memory_cols].max().max()  # 获取内存使用的最大值

    for col in memory_cols:
        ax.plot(df_memory['relative_time'], df_memory[col], label=col.replace('_', ' ').title())

    ax.set_xlabel('Time (seconds)')
    ax.set_ylabel('Memory (KiB)')
    ax.set_ylim(0, max_memory * 1.1 if max_memory > 0 else 1)
    ax.set_title('Memory Usage Over Time')
    if process_name:
        ax.text(0.5, 0.5, process_name, transform=ax.transAxes, fontsize=20, ha='center', va='center', alpha=0.7, color='black')
    ax.legend()
    ax.grid(True)
    ax.xaxis.set_major_locator(AutoLocator())
    ax.yaxis.set_major_locator(MaxNLocator(integer=True))

    return ax

# 绘制进程和线程动态曲线
def plot_process_threads(ax, df, processes, show_threads, metric='cpu'):
    for process in processes:
        df_process = df[df['command'].str.contains(process, na=False)]
        if show_threads:
            unique_pids = df_process['pid'].unique()
            for pid in unique_pids:
                df_pid = df_process[df_process['pid'] == pid]
                ax.plot(df_pid['relative_time'], df_pid[metric], label=f'{process} {metric.upper()} (PID {pid})')
        else:
            df_process_grouped = df_process.groupby('relative_time').agg({metric: 'sum'}).reset_index()
            ax.plot(df_process_grouped['relative_time'], df_process_grouped[metric], label=f'{process} (Total {metric.upper()})')
    ax.set_xlabel('Time (seconds)')
    ax.set_ylabel(f'{metric.upper()} Usage')
    ax.set_title(f'{metric.upper()} Usage of Processes and Threads Over Time')
    ax.legend()
    ax.grid(True)
    ax.xaxis.set_major_locator(AutoLocator())
    ax.yaxis.set_major_locator(MaxNLocator(integer=True))

    return ax

# 绘制图表
def plot_all(df, processes, show_threads, save_fig=False):
    for process in processes:
        fig, axes = plt.subplots(nrows=2, ncols=1, figsize=(12, 12))
        df_process = df[df['command'].str.contains(process, na=False)]
        if show_threads:
            plot_process_threads(axes[0], df_process, [process], show_threads, metric='mem')
            plot_process_threads(axes[1], df_process, [process], show_threads, metric='cpu')
        else:
            plot_memory_usage(axes[0], df, process_name=process)
            plot_process_threads(axes[1], df, [process], show_threads)

        plt.tight_layout(pad=3.0)

        if save_fig:
            fig.savefig(f'{process}_analysis.png')  # 保存图像

        plt.show()

# 主函数
def main(file_path, processes, show_threads, save_fig=False):
    df = parse_top_output(file_path)
    plot_all(df, processes, show_threads, save_fig)

# 处理命令行参数
if __name__ == "__main__":
    parser = argparse.ArgumentParser(description='Parse and plot top command output.')
    parser.add_argument('--file', type=str, required=True, help='Path to the top output file')
    parser.add_argument('--process', type=str, nargs='+', required=True, help='List of processes to plot')
    parser.add_argument('--show_threads', action='store_true', help='Show CPU and memory for all threads within the process')
    parser.add_argument('--save_fig', action='store_true', help='Save the generated plots as PNG images')

    args = parser.parse_args()
    main(args.file, args.process, args.show_threads, args.save_fig)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/763316.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

PHP电商系统开发指南高级技巧

开发高级 php 电商系统所需的技巧包括&#xff1a;数据库优化&#xff1a;使用索引、规范化数据结构和缓存机制。性能优化&#xff1a;启用页面缓存、优化图像和使用 cdn。购物车管理&#xff1a;使用会话或数据库存储数据&#xff0c;实现实时更新和弃单恢复。支付集成&#x…

windows10如何打开开发者模式

按键盘上的win键或者点击屏幕左下角的开始图标&#xff0c;即可出现如下的界面 在打开的界面中找到设置按钮&#xff0c;点击设置按钮 进入windows设置界面后&#xff0c;找到‘更新和安全’的选项&#xff0c;随后点击进入 进去后在左侧的功能列表中找到‘开发者选…

Transformer模型原理细节解析

基本原理: Transformer 的核心概念是 自注意力机制(Self-Attention Mechanism),它允许模型在处理每个输入时“关注”输入序列的不同部分。这种机制让模型能够理解每个单词或符号与其他单词或符号之间的关系,而不是逐个地线性处理输入。 Transformer 主要由两个部分组成:…

推荐算法学习笔记2.1:基于深度学习的推荐算法-基于共线矩阵的深度推荐算法-AutoRec模型

AutoRec模型 前置知识&#xff1a;推荐算法学习笔记1.1:传统推荐算法-协同过滤算法 AutoRec模型通过引入自编码器结构&#xff0c;将共线矩阵中的用户向量&#xff08;基于用户的U-AutoRec&#xff09;或物品向量&#xff08;基于物品的I-AutoRec&#xff09;嵌入到低维空间后还…

Ubuntu24.04LTS基础软件下载

librewolf: deb文件link 作用&#xff1a;访问github&#xff0c;无痕浏览&#xff0c;这个速度&#xff0c;不指望了 vscodium: 从deb安装&#xff0c;ubuntu sudo dpkg -i xxx.debpaste-image 插件替代 markdown wps: libreoffice: 替换USTC源 sudo nano /etc/apt/sourc…

Objective-C语法基础

新建一个XCode项目 新建一个类 1、成员变量、属性 1.1、类内使用成员变量&#xff0c;类外使用属性 Role.h #import <Foundation/Foundation.h>NS_ASSUME_NONNULL_BEGINinterface Role : NSObject {//成员变量&#xff1a;只能类内使用NSString *_name;int _age; }//属…

GOM引擎源码 完整可编译 带微端 附带基础附件

GOM引擎源码 完整可编译 带微端 附带基础附件 时间紧迫&#xff0c;无暇顾及&#xff0c;无意中得到即公布GameOfMir源码未测试&#xff0c;专业人事自行编译测试&#xff01;非诚勿扰&#xff01;源码下载&#xff1a;极速云

招生报名系统教培招生小程序

招生报名系统&#xff1a;轻松实现教培招生新高度 &#x1f680; 招生报名系统&#xff0c;开启智慧教育新时代 在当今数字化快速发展的时代&#xff0c;教育行业也迎来了变革的浪潮。招生报名系统作为这一变革的先锋&#xff0c;为教育机构提供了全新的招生渠道和管理方式。通…

Spring Boot集成DeepLearning4j实现图片数字识别

1.什么是DeepLearning4j&#xff1f; DeepLearning4J&#xff08;DL4J&#xff09;是一套基于Java语言的神经网络工具包&#xff0c;可以构建、定型和部署神经网络。DL4J与Hadoop和Spark集成&#xff0c;支持分布式CPU和GPU&#xff0c;为商业环境&#xff08;而非研究工具目的…

【前端CSS3】一篇搞懂各类常用选择器(黑马程序员)

文章目录 一、前言&#x1f680;&#x1f680;&#x1f680;二、正文&#xff1a;2.1 基础选择器2.1.1 标签选择器2.1.2 类选择器2.1.3 id选择器2.1.4 通配符选择题2.1.5 类选择器与id选择器区别☀️☀️☀️2.1.6 基础选择器总结&#x1f680; 2.2 复合类选择器2.2.1 后代选择…

Python | Leetcode Python题解之第191题位1的个数

题目&#xff1a; 题解&#xff1a; class Solution:def hammingWeight(self, n: int) -> int:ret 0while n:n & n - 1ret 1return ret

Unity 功能 之 创建 【Unity Package】 Manager 自己自定义管理的包的简单整理

Unity 功能 之 创建 【Unity Package】 Manager 自己自定义管理的包的简单整理 一、简单介绍 Unity Package 是一种模块化的资源管理和分发方式&#xff0c;用于将游戏开发所需的代码、资源、配置文件等内容打包成一个独立的、可重用的组件。Unity Package 可以在多个项目之间…

【RabbitMQ问题踩坑】RabbitMQ设置手动ack后,消息队列有多条消息,只能消费一条,就不继续消费了,这是为什么 ?

现象&#xff1a;我发送5条消息到MQ队列中&#xff0c;同时&#xff0c;我在yml中设置的是需要在代码中手动确认&#xff0c;但是我把代码中的手动ack给关闭了&#xff0c;会出现什么情况&#xff1f; yml中配置&#xff0c;配置需要在代码中手动去确认消费者消费消息成功&…

Tomcat部署与优化

Tomcat部署与优化 Tomcat简述 server&#xff1a; 服务器&#xff0c;Tomcat运行的进程实例&#xff0c;一个Server中可以有多个service&#xff0c;但通常就一个 service&#xff1a;服务&#xff0c;用来组织Engine&#xff08;引擎&#xff09;和Connector&#xff08;连接…

黑鹰优化算法(BEO)-2024年SCI新算法-公式原理详解与性能测评 Matlab代码免费获取

目录 原理简介 一、种群初始化 二、围捕行为 三、悬停行为 四、捕捉行为 五、抢夺行为 六、警告行为 七、迁徙行为 八、求偶行为 九、孵化行为 性能测评 参考文献 完整代码 黑鹰优化算法(Black eagle optimizer, BEO)是一种新型的元启发式算法&#xff08;智能优化…

微信小程序的运行机制与更新机制

1. 小程序运行机制 1.1. 冷启动与热启动 冷启动为用户第一次打开小程序时&#xff0c;因为之前没有打开过&#xff0c;这是第一种冷启动的情兑。第二种情况为虽然之前用户打开过&#xff0c;但是小程序被用户主动的销毁过&#xff0c;这种情况下我们再次打开小程序&#xff0…

PADS设置板框提示不闭合的解决办法

一般是选中join&#xff0c;提示不闭合&#xff0c;不能转成板框&#xff0c;其实直接点击close就好了&#xff0c;报错提示里就有提示&#xff0c;让用close命令试试

FT232串口win11打不开,重新安装驱动问题解决。

问题现象&#xff1a;FT232 WIN11打不开&#xff0c;串口识别正在被占用。更改串口号问题无法解决。 解决办法&#xff1a; 卸载驱动&#xff0c; 重启电脑&#xff0c; 去官网下驱动安装问题解决。Drivers - FTDI

卡尔曼滤波公式推导笔记

视频见B站上DR_CAN的卡尔曼滤波器 【卡尔曼滤波器】3_卡尔曼增益超详细数学推导 &#xff5e;全网最完整_哔哩哔哩_bilibili

虚拟机网络配置(静态网络)

解决问题&#xff1a;VMware中创建centOS虚拟机后使用ifconfig没有ip地址&#xff0c;但我想在主机&#xff08;Windows&#xff09;系统下使用shell连接虚拟机从而方便后续交互。 VMware中编辑->虚拟网络编辑器 &#xff08;注意需要管理员身份不然会无法修改&#xff09;…