看所有网卡参数,确认 RM520N-GL 网卡

测试原理

udevadm info /sys/class/net/ifconfig

读取所有网卡程序

复制代码
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import os
import subprocess


def run_cmd(cmd):
    try:
        result = subprocess.run(
            cmd,
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
            text=True
        )
        if result.returncode == 0:
            return result.stdout.strip()
        err = result.stderr.strip()
        return f"Error: {err}" if err else "Error: command failed"
    except Exception as e:
        return f"Exception occurred: {str(e)}"


def get_all_ifconfig():
    return run_cmd(["ifconfig", "-a"])


def get_iface_udevadm_info(ifname):
    return run_cmd(["udevadm", "info", f"/sys/class/net/{ifname}"])


def list_ifaces():
    try:
        ifaces = os.listdir("/sys/class/net")
        ifaces.sort()
        return ifaces
    except Exception as e:
        print(f"读取网卡列表失败: {e}")
        return []


if __name__ == "__main__":
    print("=" * 80)
    print("ifconfig -a 输出")
    print("=" * 80)
    print(get_all_ifconfig())
    print()

    ifaces = list_ifaces()
    if not ifaces:
        print("没有读取到网卡")
    else:
        for ifname in ifaces:
            print("=" * 80)
            print(f"网卡: {ifname}")
            print("=" * 80)
            print(get_iface_udevadm_info(ifname))
            print()

UI 网页程序

复制代码
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
 
import os
import socket
import fcntl
import struct
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
import subprocess
import html
import time
 
PORT = 12315
 
 
def get_iface_ip(ifname):
    s = None
    try:
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        return socket.inet_ntoa(
            fcntl.ioctl(
                s.fileno(),
                0x8915,
                struct.pack("256s", ifname[:15].encode("utf-8"))
            )[20:24]
        )
    except Exception:
        return ""
    finally:
        if s:
            s.close()


def get_iface_netmask(ifname):
    s = None
    try:
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        return socket.inet_ntoa(
            fcntl.ioctl(
                s.fileno(),
                0x891b,
                struct.pack("256s", ifname[:15].encode("utf-8"))
            )[20:24]
        )
    except Exception:
        return ""
    finally:
        if s:
            s.close()


def read_file(path):
    try:
        with open(path, "r", encoding="utf-8", errors="ignore") as f:
            return f.read().strip()
    except Exception:
        return ""


def run_cmd(cmd):
    try:
        r = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True)
        return r.stdout.strip()
    except Exception as e:
        return f"命令执行失败: {e}"


def list_ifaces():
    try:
        names = os.listdir("/sys/class/net")
        names.sort()
        return names
    except Exception:
        return []


def get_iface_mac(ifname):
    return read_file(f"/sys/class/net/{ifname}/address")


def get_iface_state(ifname):
    return read_file(f"/sys/class/net/{ifname}/operstate")


def get_iface_mtu(ifname):
    return read_file(f"/sys/class/net/{ifname}/mtu")


def get_iface_type(ifname):
    t = read_file(f"/sys/class/net/{ifname}/type")
    type_map = {
        "1": "Ethernet",
        "24": "Loopback",
        "32": "IPIP",
        "512": "PPP",
        "768": "Tunnel",
        "772": "Loopback",
        "801": "IEEE802.11",
    }
    return type_map.get(t, t if t else "未知")


def get_iface_speed(ifname):
    v = read_file(f"/sys/class/net/{ifname}/speed")
    return v if v else ""


def get_iface_duplex(ifname):
    return read_file(f"/sys/class/net/{ifname}/duplex")


def get_iface_carrier(ifname):
    return read_file(f"/sys/class/net/{ifname}/carrier")


def get_iface_ipv6_list(ifname):
    result = []
    try:
        with open("/proc/net/if_inet6", "r", encoding="utf-8", errors="ignore") as f:
            for line in f:
                parts = line.strip().split()
                if len(parts) >= 6 and parts[5] == ifname:
                    raw = parts[0]
                    addr = socket.inet_ntop(socket.AF_INET6, bytes.fromhex(raw))
                    prefix = int(parts[2], 16)
                    result.append(f"{addr}/{prefix}")
    except Exception:
        pass
    return result


def get_iface_ipv4_list(ifname):
    result = []
    out = run_cmd(["ip", "-o", "-4", "addr", "show", "dev", ifname])
    if out.startswith("命令执行失败") or not out:
        ip = get_iface_ip(ifname)
        if ip:
            mask = get_iface_netmask(ifname)
            if mask:
                result.append(f"{ip} / {mask}")
            else:
                result.append(ip)
        return result

    for line in out.splitlines():
        parts = line.split()
        if "inet" in parts:
            idx = parts.index("inet")
            if idx + 1 < len(parts):
                result.append(parts[idx + 1])
    return result


def classify_udev_key(key):
    basic_keys = {
        "DEVPATH", "DEVNAME", "DEVTYPE", "SUBSYSTEM", "IFINDEX", "INTERFACE",
        "MAJOR", "MINOR", "ACTION", "SEQNUM", "USEC_INITIALIZED"
    }
    if key in basic_keys:
        return "基础信息"

    if key.startswith("ID_NET_NAME") or key.startswith("ID_NET_LABEL") or key in {"ID_RENAMING", "ID_NET_DRIVER"}:
        return "命名信息"

    if (
        key.startswith("ID_USB") or
        key.startswith("ID_VENDOR") or
        key.startswith("ID_MODEL") or
        key.startswith("ID_PATH") or
        key.startswith("ID_PCI") or
        key.startswith("PCI_") or
        key in {"ID_BUS", "DRIVER", "MODALIAS"}
    ):
        return "总线硬件"

    if (
        key.startswith("ID_NET_") or
        key in {
            "ADDR_ASSIGN_TYPE", "ADDR_LEN", "BROADCAST", "CARRIER", "CARRIER_CHANGES",
            "CARRIER_UP_COUNT", "CARRIER_DOWN_COUNT", "SPEED", "DUPLEX", "MTU",
            "TX_QUEUE_LEN", "LINK_FILE"
        }
    ):
        return "网络属性"

    return "其他属性"


def get_udevadm_grouped(ifname):
    raw = run_cmd(["udevadm", "info", f"/sys/class/net/{ifname}"])
    groups = {
        "基础信息": [],
        "系统路径": [],
        "命名信息": [],
        "总线硬件": [],
        "网络属性": [],
        "其他属性": [],
        "符号链接": [],
    }

    if raw.startswith("命令执行失败"):
        groups["其他属性"].append(("错误", raw))
        return groups

    for line in raw.splitlines():
        line = line.strip()
        if not line or len(line) < 2 or line[1] != ":":
            continue

        prefix = line[:2]
        value = line[2:].strip()

        if prefix == "P:":
            groups["系统路径"].append(("DEVPATH", value))
        elif prefix == "M:":
            groups["基础信息"].append(("内核名", value))
        elif prefix == "R:":
            groups["基础信息"].append(("设备号", value))
        elif prefix == "U:":
            groups["基础信息"].append(("子系统", value))
        elif prefix == "T:":
            groups["基础信息"].append(("类型", value))
        elif prefix == "D:":
            groups["基础信息"].append(("设备节点", value))
        elif prefix == "N:":
            groups["命名信息"].append(("当前网卡名", value))
        elif prefix == "L:":
            groups["符号链接"].append(("优先级", value))
        elif prefix == "S:":
            groups["符号链接"].append(("别名路径", value))
        elif prefix == "E:":
            if "=" in value:
                k, v = value.split("=", 1)
                groups[classify_udev_key(k)].append((k, v))
            else:
                groups["其他属性"].append(("属性", value))

    return groups


def get_host_ips():
    result = []
    for ifname in list_ifaces():
        ip = get_iface_ip(ifname)
        if ip:
            result.append((ifname, ip))
    return result


def render_kv_table(items):
    if not items:
        return '<div class="empty">无</div>'

    rows = []
    for k, v in items:
        rows.append(
            f"<tr><td>{html.escape(str(k))}</td><td>{html.escape(str(v))}</td></tr>"
        )
    return '<table class="kv">' + "".join(rows) + "</table>"


def render_udev_sections(groups, ifname):
    order = ["基础信息", "系统路径", "命名信息", "总线硬件", "网络属性", "其他属性", "符号链接"]
    blocks = []
    for name in order:
        blocks.append(f"""
        <details class="subbox" open>
          <summary>{html.escape(name)}</summary>
          {render_kv_table(groups.get(name, []))}
        </details>
        """)
    return f"""
    <details class="udev-box" open>
      <summary>查看整理后的 udevadm 信息:/sys/class/net/{html.escape(ifname)}</summary>
      {''.join(blocks)}
    </details>
    """


def build_iface_card(ifname):
    ip4_list = get_iface_ipv4_list(ifname)
    ipv6_list = get_iface_ipv6_list(ifname)
    mac = get_iface_mac(ifname)
    state = get_iface_state(ifname)
    mtu = get_iface_mtu(ifname)
    speed = get_iface_speed(ifname)
    duplex = get_iface_duplex(ifname)
    carrier = get_iface_carrier(ifname)
    iftype = get_iface_type(ifname)
    udev_groups = get_udevadm_grouped(ifname)

    ip4_html = "<br>".join(html.escape(x) for x in ip4_list) if ip4_list else "无"
    ip6_html = "<br>".join(html.escape(x) for x in ipv6_list) if ipv6_list else "无"

    return f"""
    <div class="card">
      <div class="title">{html.escape(ifname)}</div>
      <table class="main">
        <tr><td>类型</td><td>{html.escape(iftype)}</td></tr>
        <tr><td>状态</td><td>{html.escape(state) if state else '未知'}</td></tr>
        <tr><td>载波</td><td>{'已连接' if carrier == '1' else ('未连接' if carrier == '0' else '未知')}</td></tr>
        <tr><td>MAC</td><td>{html.escape(mac) if mac else '无'}</td></tr>
        <tr><td>MTU</td><td>{html.escape(mtu) if mtu else '未知'}</td></tr>
        <tr><td>IPv4</td><td>{ip4_html}</td></tr>
        <tr><td>IPv6</td><td>{ip6_html}</td></tr>
        <tr><td>Speed</td><td>{html.escape(speed) + ' Mb/s' if speed else '未知'}</td></tr>
        <tr><td>Duplex</td><td>{html.escape(duplex) if duplex else '未知'}</td></tr>
      </table>
      {render_udev_sections(udev_groups, ifname)}
    </div>
    """


def build_page():
    iface_names = list_ifaces()
    cards = "".join(build_iface_card(name) for name in iface_names)

    ip_links = []
    for ifname, ip in get_host_ips():
        ip_links.append(
            f'<a href="http://{html.escape(ip)}:{PORT}" target="_blank">{html.escape(ifname)}: {html.escape(ip)}</a>'
        )

    ip_links_html = "<br>".join(ip_links) if ip_links else "未检测到可访问 IPv4"
    now = time.strftime("%Y-%m-%d %H:%M:%S")

    return f"""<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>网卡信息</title>
<style>
body {{
    margin: 0;
    padding: 20px;
    font-family: Arial, "Microsoft YaHei", sans-serif;
    background: #f5f7fb;
    color: #222;
}}
.wrap {{
    max-width: 1280px;
    margin: 0 auto;
}}
.top {{
    background: #fff;
    border-radius: 14px;
    padding: 18px;
    box-shadow: 0 2px 12px rgba(0,0,0,.08);
    margin-bottom: 18px;
}}
h1 {{
    margin: 0 0 10px 0;
    font-size: 28px;
}}
.muted {{
    color: #666;
    font-size: 14px;
}}
.grid {{
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(380px, 1fr));
    gap: 16px;
}}
.card {{
    background: #fff;
    border-radius: 14px;
    padding: 16px;
    box-shadow: 0 2px 12px rgba(0,0,0,.08);
}}
.title {{
    font-size: 22px;
    font-weight: bold;
    margin-bottom: 12px;
    color: #0b57d0;
}}
table {{
    width: 100%;
    border-collapse: collapse;
}}
.main td {{
    border-bottom: 1px solid #eee;
    padding: 8px 6px;
    vertical-align: top;
    word-break: break-all;
}}
.main td:first-child {{
    width: 90px;
    color: #666;
}}
.kv td {{
    border-bottom: 1px solid #f0f0f0;
    padding: 7px 6px;
    vertical-align: top;
    word-break: break-all;
}}
.kv td:first-child {{
    width: 160px;
    color: #666;
}}
details {{
    margin-top: 10px;
}}
summary {{
    cursor: pointer;
    color: #0b57d0;
    user-select: none;
}}
.udev-box {{
    margin-top: 12px;
    padding-top: 6px;
}}
.subbox {{
    background: #fafbff;
    border: 1px solid #edf1f7;
    border-radius: 10px;
    padding: 8px 10px;
    margin-top: 10px;
}}
.empty {{
    color: #888;
    padding: 6px 2px;
}}
a {{
    color: #0b57d0;
    text-decoration: none;
}}
</style>
</head>
<body>
<div class="wrap">
  <div class="top">
    <h1>所有网卡信息</h1>
    <div class="muted">刷新时间:{html.escape(now)}</div>
    <div style="margin-top:10px;"><b>访问地址</b><br>{ip_links_html}</div>
  </div>

  <div class="grid">
    {cards if cards else '<div class="card">没有读取到网卡</div>'}
  </div>
</div>
</body>
</html>"""


class Handler(BaseHTTPRequestHandler):
    def do_GET(self):
        body = build_page()
        data = body.encode("utf-8")
        self.send_response(200)
        self.send_header("Content-Type", "text/html; charset=utf-8")
        self.send_header("Content-Length", str(len(data)))
        self.end_headers()
        self.wfile.write(data)

    def log_message(self, format, *args):
        return


if __name__ == "__main__":
    server = ThreadingHTTPServer(("0.0.0.0", PORT), Handler)
    print(f"访问地址: http://0.0.0.0:{PORT}")
    for ifname, ip in get_host_ips():
        print(f"http://{ip}:{PORT}    [{ifname}]")
    server.serve_forever()
相关推荐
会飞的胖达喵2 小时前
基于qt开发的RedisDesk
开发语言·qt
qq_189807032 小时前
c++怎么解决ifstream在读取UTF-16文件时的乱码_imbue用法【避坑】
jvm·数据库·python
不过如此19512 小时前
pyinstaller打包GUI项目实践
windows·python·ui
油炸自行车2 小时前
【Qt】运行 `windeployqt.exe` 打包Qt发布包,遇到警告的解决方法 (Warning: Cannot find any.....)
开发语言·qt·vs·打包·windeployqt·软件部署
yu85939582 小时前
C++ 虚拟磁盘与虚拟光驱实现
开发语言·c++
青苔猿猿2 小时前
【3】jupyter单元格Cell操作
python·jupyter·单元格
阿凤212 小时前
后端返回数据流的格式
开发语言·前端·javascript·uniapp
Matlab程序猿小助手2 小时前
【MATLAB源码-第315期】基于matlab的䲟鱼优化算法(ROA)无人机三维路径规划,输出做短路径图和适应度曲线.
开发语言·算法·matlab
Tingjct2 小时前
C++ 多态
java·开发语言·c++