手写小型网络管理系统:设备发现、SNMP采集与数据库设计全解析

📅 发布时间:2026/9/12 15:18:38
手写小型网络管理系统:设备发现、SNMP采集与数据库设计全解析
简介这是一套基于SpringBoot的企业内部小型网络管理系统毕业设计项目面向计算机专业正在完成毕业设计、期末大作业或需要项目实战练习的学习者。系统采用前后端分离模式后端SpringBoot处理业务逻辑前端Vue.js实现交互核心模块包括用户权限管理、网络设备状态监控、告警记录和故障诊断能够完整覆盖企业网络管理的基本场景。压缩包共411个文件约11.1MB以java、vue、svg、xml、sql、docx/doc等类型为主既有可运行源码也有论文、开发说明和数据库设计文档结构清楚便于对照学习。其中sql文件描述表结构与索引设计docx/doc为论文和开发文档源码均经过本地编译调试可辅助理解接口设计、模块划分和数据库建模。当前已有40人浏览学习难度适中且经过导师审定适合用作课程设计参考或SpringBoot实战入门。1. 企业内部小型网络管理系统为什么还要自己写源码网络设备数量超过二十台以后靠Excel登记IP、在命令行里挨个ping的日子就很难维持。商业网管软件功能虽然齐全价格、部署成本和运维门槛对小微企业并不友好通用开源监控平台又像瑞士军刀什么都有但设备台账、告警记录、权限这些内部管理习惯往往得改一堆模板才能贴近实际使用方式。这时自己实现一个小型网络管理系统反而是更务实的选择把设备发现、SNMP采集、数据库存储和告警展示控制在能维护的范围最后形成源码、论文、说明文档、数据库文档一套完整交付物。这条路要回答的是“系统怎么设计、数据库怎么建、代码怎么写”三个问题。适合网管、运维以及拿网络管理做数据库课程设计的工程师下面完整展开。2. 网络管理系统的功能边界与整体架构设计2.1 先想清楚小型网络管理系统管设备不包办业务为避免体系庞大我通常建议把对象限制在局域网内部。设备种类三到五类交换机、路由器、无线接入点、服务器、网络打印机数量在几十台到四百台之间。管理范围拆成四件事第一设备发现根据IP段扫描新增设备更新设备列表。第二状态监控通过ICMP和SNMP采集在线状态、接口流量、CPU内存等指标。第三事件告警设备掉线、接口状态翻转、流量超阈值时生成告警。第四配置记录定期备份交换机的running-config保留变更痕迹。把这些功能之外的配置批量下发、流量行为分析等内容挡在系统外能省下大量定制工作论文里的需求分析也好写不容易被评审追问到无法落地的方案。版本上建议分两期。第一期只做三件事设备列表自动发现、每台设备每5分钟ping一次、连续3次掉线后生成告警。第二期再加入SNMP接口流量采集和Web展示。很多失败项目都是因为一开始把告警、报表、拓扑图全排进一期结果连“设备能ping通”这条主干都没做完验收时拿不出可用功能。这种分期方式也决定了文档结构系统设计、数据库设计、系统测试各占一块每一条结论都有对应模块支撑不会出现论文写了而源码里没有实现的情况。2.2 分层结构采集、存储、告警、展示不要耦合在一起常见错误是写一个while循环把ping、SNMP、数据库写入和页面渲染全串起来。一台设备SNMP超时拖到5秒后面几十台设备全部排队整套页面的响应时间也跟着受影响。更可靠的做法是分四层。采集层使用定时任务分别处理ICMP和SNMP无论设备多久没响应只影响当前采集任务。数据处理层负责阈值判断、告警去重和指标格式转换不在采集层里面拼SQL。存储层保存设备台账、接口历史数据、告警事件尽量让写入和查询互不阻塞。展示层做设备列表、状态面板和拓扑关系展示通过API读取数据不直接碰采集任务内部结构。分层之后采集进程重启不会影响查询服务要重放历史告警也只需要在数据处理层重新跑对应的历史数据。2.3 SNMP轮询和客户端主动上报怎么选小型网络管理系统最常见的采集方案是SNMP轮询。交换机、路由器、打印机基本都支持SNMP启用后配置只读的社区字符串就能拿到基础接口计数和系统信息。它的优势在于不需要在被管设备上安装额外程序维护成本低。但每次轮询都会消耗设备CPU建议周期放在1到5分钟不要秒级轮询。对于Linux服务器可以额外让被管端采集脚本上报内存和磁盘数据因为通用SNMP OID拿不到进程级信息。核心原则是网络设备一律用SNMP服务器可以叠加轻量上报。采集方式适用对象优势主要问题SNMP轮询交换机、路由器、打印机无需安装客户端标准OID轮询频率过高会增加设备负载客户端主动上报Linux服务器、Windows主机能拿进程、磁盘细粒度指标需要维护上报脚本升级一次牵一发动全身ICMP ping全部IP设备最快判断在线状态只能判断可达性拿不到业务数据实际项目中要特别注意SNMP安全v2c的社区字符串是明文传输只应在内网使用支持v3的设备优先开启认证和加密但老款交换机可能不支持v3要做兼容降级处理。2.4 源码目录规划与交付物对应关系代码结构在动工前先定好后续写说明文档和论文才有依据。常见做法是采集、存储、告警、展示分目录数据库脚本单独放文档单独放。参考目录nms/ ├── collector/ │ ├── discovery.py # 设备发现 │ ├── icmp_ping.py # 可用性检测 │ └── snmp_collect.py # 接口流量、CPU采集 ├── database/ │ ├── schema.sql # 建库建表脚本 │ └── db_pool.py # 数据库连接池 ├── alert/ │ └── rule_engine.py # 阈值规则与告警去重 ├── web/ │ ├── app.py # Flask或FastAPI入口 │ └── templates/ # 页面模板 ├── docs/ │ ├── 说明文档.md # 部署、配置、启动方式 │ └── 论文结构.md # 章节大纲与素材索引 └── requirements.txt这个目录里collector和alert是核心源码database/schema.sql是数据库文档的基石docs下的说明文档和论文结构用于整套交付物评审。注意collector只做采集和解析不负责直接写业务表写库动作统一交给alert和web层否则时间一久会在多处看到重复的数据库增删改查逻辑后续维护成本会明显上升。3. 数据库设计网络管理系统的数据模型与SQL脚本3.1 设备、接口、告警三张核心表怎么建网络管理系统数据库设计不需要几百张表小系统里最关键的实体是设备、接口、告警以及它们之间的引用关系。把设备表建好后续的拓扑表和操作日志才有依附点把接口表设计成与设备一对多才能保存各个接口的历史流量告警表采用事件写入而不是覆盖更新便于统计故障时长和恢复时间。下面是最小的建表脚本开发阶段完全够用CREATE TABLE device ( device_id INT AUTO_INCREMENT PRIMARY KEY, device_name VARCHAR(64) NOT NULL, ip_address VARCHAR(45) NOT NULL UNIQUE, vendor VARCHAR(32), model VARCHAR(32), snmp_version VARCHAR(8) DEFAULT 2c, snmp_community VARCHAR(32), location VARCHAR(128), status TINYINT DEFAULT 0 COMMENT 0为离线1为在线, last_seen DATETIME, created_at DATETIME DEFAULT CURRENT_TIMESTAMP ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; CREATE TABLE interface ( interface_id INT AUTO_INCREMENT PRIMARY KEY, device_id INT NOT NULL, if_index INT NOT NULL, if_name VARCHAR(64), if_speed BIGINT, if_oper_status TINYINT DEFAULT 0 COMMENT 0 down1 up, if_in_octets BIGINT, if_out_octets BIGINT, collect_time DATETIME, KEY idx_device_time (device_id, collect_time), CONSTRAINT fk_interface_device FOREIGN KEY (device_id) REFERENCES device(device_id) ON DELETE CASCADE ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; CREATE TABLE alarm ( alarm_id INT AUTO_INCREMENT PRIMARY KEY, device_id INT NOT NULL, alarm_type VARCHAR(32), level TINYINT DEFAULT 3 COMMENT 1紧急2重要3一般, description VARCHAR(255), status TINYINT DEFAULT 0 COMMENT 0未确认1已确认2已恢复, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, ack_user VARCHAR(32), ack_time DATETIME, KEY idx_device_time (device_id, create_time), CONSTRAINT fk_alarm_device FOREIGN KEY (device_id) REFERENCES device(device_id) ON DELETE CASCADE ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;三个表的说明device里status是实时状态缓存last_seen记录最后一次成功采集时间页面上拿来判断设备离线时长。interface表中的流量字段是累计计数实际速率需要对比两次采集差值再除以间隔不能直接拿octet数值当带宽展示。alarm表独立存放告警事件不随设备状态覆盖方便统计故障次数。外键约束可以保留但如果设备量超过五百台建议去掉接口表和告警表外的外键改为应用层保证一致性减少锁竞争。3.2 设备入库与状态更新用UPSERT避免重复记录设备发现跑完之后会拿到一批IP、设备名和位置信息。由于多次扫描会有重复插入时不能简单用INSERT最好是带唯一键的UPSERT让同一IP只保留一条设备记录# collector/discovery.py 中的入库片段 def upsert_device(conn, ip, name, location): sql INSERT INTO device(ip_address, device_name, location, status, last_seen) VALUES(%s, %s, %s, 1, NOW()) ON DUPLICATE KEY UPDATE device_name %s, location %s, status 1, last_seen NOW() cur conn.cursor() cur.execute(sql, (ip, name, location, name, location)) conn.commit()这段代码对应的是数据库文档里最常出现的“新增设备、更新在线状态”流程。ip_address上有唯一约束所以重复扫描不会新开记录只会更新设备名和最后一次出现时间。status1同时把设备标记为在线如果下次扫描没再发现该IP再由离线任务把它改回0两次状态变更之间留出时间差避免一秒钟内抖动。3.3 用数据库连接池撑住轮询采集的并发写采集层通常是按设备分发的多线程任务每个任务都要查询和写入数据库。如果每个线程启动时都新建连接数据库端会在一轮扫描开始时突然出现几十个TIME_WAIT连接整体性能明显下降。推荐使用DBUtils.PooledDB在一个Python进程里维护连接池。# database/db_pool.py from dbutils.pooled_db import PooledDB import pymysql pool PooledDB( creatorpymysql, maxconnections20, mincached2, maxcached10, blockingTrue, setsession[], charsetutf8mb4, host127.0.0.1, port3306, usernms, passwordnms_pass, databasenms ) def get_conn(): return pool.connection()参数说明maxconnections20表示连接池最多保持20个连接超过后blockingTrue会等待而不是直接报错mincached2表示启动时保持2个空闲连接避免每轮采集都要重新握手maxcached10是空闲连接上限。连接池不能跨进程共享采集层如果用多进程部署每个进程要独立实例化。取出的连接用完要归还不要调用close()否则会把池里的连接关掉后续任务只能重新建连。3.4 历史数据保留与数据库同步的取舍网络管理系统的数据库会随采集周期快速膨胀。以100台设备、每台5个接口、每5分钟采集一次为例一天产生约14万条接口计数记录。这类数据的价值随时间递减没有必须全部原样保留。常见做法是原始值保留30天聚合值保留一年。可以建立定时任务把超过30天数据按小时汇聚后写入interface_hourly表再删除原始记录。数据类型保留周期存储方式接口流量原始值30天按日分区表接口流量小时聚合值1年独立聚合表告警事件1年不清理按年归档设备在线状态90天只保留状态变化时间点如果多个小型站点独立部署后需要集中查看可以通过数据库同步工具把各站点的告警表单向同步到总部不要在采集层强行打通网络。同步时要注意主键冲突最省心的方案是给每个站点设置不同的device_id偏移或者在设备表里增加site_id字段。这一节的取舍建议直接写进数据库文档方便后续维护人员理解为什么不是所有数据都永久保留。4. 网络管理系统的采集与告警实现从Ping到SNMP4.1 设备发现用ARP表加Ping扫描找出新设备网络发现不要直接对整个C段做暴力ping那样结果不准确还会给接入层交换机造成压力。更可靠做法是分两步先读取核心交换机或网关设备的ARP表拿到当前活跃的IP与MAC映射再对其中不存在的IP做一次轻量ping确认最终把结果写入设备表。下面这段代码是发现模块的核心按IP段扫描并返回可达地址# collector/discovery.py import ipaddress import platform import subprocess from concurrent.futures import ThreadPoolExecutor, as_completed def ping(ip, timeout1): if platform.system().lower() windows: cmd [ping, -n, 1, -w, str(timeout * 1000), str(ip)] else: cmd [ping, -c, 1, -W, str(timeout), str(ip)] return subprocess.call(cmd, stdoutsubprocess.DEVNULL, stderrsubprocess.DEVNULL) 0 def scan_subnet(network): net ipaddress.ip_network(network, strictFalse) results [] with ThreadPoolExecutor(max_workers32) as executor: futures {executor.submit(ping, str(ip)): ip for ip in net.hosts()} for future in as_completed(futures): ip futures[future] if future.result(): results.append(str(ip)) return resultsThreadPoolExecutor(max_workers32)最多同时跑32个ping避免把网管机自己打满。timeout1表示单次ping等待1秒网络较大时建议提高到2秒但要降低并发数。返回值只包含可达的IP后续还要调用SNMP拿设备名和厂商信息才能生成完整的设备记录。注意ping结果只代表IP层可达不能判断SNMP协议是否开放所以新设备入库后要立刻做一次SNMP探测失败的设备标记为“只监控在线状态”。4.2 SNMP采集接口流量与状态的关键OID网络管理系统里最常用的是系统组和接口组。第一版优先实现以下OID指标对象OID说明sysName1.3.6.1.2.1.1.5.0设备主机名sysUpTime1.3.6.1.2.1.1.3.0设备运行时长ifIndex1.3.6.1.2.1.2.2.1.1接口索引ifDescr1.3.6.1.2.1.2.2.1.2接口描述ifOperStatus1.3.6.1.2.1.2.2.1.8接口运作状态ifInOctets1.3.6.1.2.1.2.2.1.10接口入方向累计字节ifOutOctets1.3.6.1.2.1.2.2.1.16接口出方向累计字节通过pysnmp读取单个OID的代码# collector/snmp_collect.py from pysnmp.hlapi import * def snmp_get(ip, community, oid, port161): iterator getCmd( SnmpEngine(), CommunityData(community, mpModel1), UdpTransportTarget((ip, port), timeout2, retries1), ContextData(), ObjectType(ObjectIdentity(oid)) ) errorIndication, errorStatus, errorIndex, varBinds next(iterator) if errorIndication or errorStatus: return None return varBinds[0][1].prettyPrint()参数含义CommunityData(community, mpModel1)中mpModel1表示SNMPv2c老设备可改成mpModel0切换v1timeout2, retries1表示单次尝试2秒失败重试1次单个设备采集时间不应超过6秒。返回值是字符串接口流量是32位计数器超过约4GB会归零计算速率时必须处理回绕当前值小于上一次值时用当前值加上2^32再减上一次值。CPU占用率厂商差异大建议在device表里增加cpu_oid字段让每台设备单独配置第一版可以先不做CPU不是所有设备都支持用同一套规则读。4.3 告警规则用滑动窗口避免告警风暴告警不是“ping不通就发一条”那样一次断网会产生海量重复事件。更实用的规则是连续检测3次失败才生成设备离线告警恢复时连续2次成功同一设备同一告警类型在10分钟内不重复上报。下面是规则引擎核心逻辑# alert/rule_engine.py from collections import deque from datetime import datetime, timedelta class AlarmRuleEngine: def __init__(self): self.fail_window deque(maxlen3) self.ok_window deque(maxlen2) self.last_alarm_at {} def check(self, device_id, is_up): self.fail_window.append(0 if is_up else 1) self.ok_window.append(1 if is_up else 0) now datetime.now() if sum(self.fail_window) 3: last self.last_alarm_at.get(device_id) if not last or (now - last) timedelta(minutes10): self.last_alarm_at[device_id] now return {level: 3, type: DEVICE_DOWN, description: f{device_id} 连续3次检测失败} if sum(self.ok_window) 2: self.last_alarm_at.pop(device_id, None) return Nonefail_window保留最近3次结果只有3次全部失败才触发告警避免单次网络抖动误报ok_window保留最近2次连续两次成功就认为设备恢复同时清掉告警状态。last_alarm_at记录上一次告警生成时间10分钟内重复故障只保留一条减少告警风暴。这个类由采集线程每分钟调用一次告警入库放在调用方做不要在check方法里连数据库否则并发高时会出现重复写告警表的情况。5. 交付前的自检把源码、数据库文档和论文串起来验证5.1 核对zip包里的数据库文档与建表脚本拿到带有源码、论文、说明文档、数据库文档的压缩包后最先要做的不是启动程序而是验证内部一致性。常见情况是schema.sql已经加了新表说明文档里的数据库字段却还是旧版或者论文里写了告警优化代码里根本没有对应模块。可以写一个简单脚本读取数据库文档中的表名与schema.sql和源码里的SQL语句比对。# tools/check_delivery.py import re def extract_table_names(sql_text): return set(re.findall(rCREATE TABLE\s(\w), sql_text, re.I)) schema_path database/schema.sql doc_path docs/数据库文档.md tables_in_schema extract_table_names(open(schema_path, encodingutf-8).read()) tables_in_doc set(re.findall(r(\w)\s*表, open(doc_path, encodingutf-8).read())) missing tables_in_schema - tables_in_doc if missing: print(数据库文档未覆盖的表:, missing) else: print(schema与数据库文档一致)脚本解析建表语句中的表名再去数据库文档里找“xxx表”这种写法。正则不需要写得很全只要能暴露明显不一致就够了。真正的数据库文档还应包含关键索引和字段注释不只是表名清单。脚本检查通过后按说明文档里的步骤启动服务避免把配置错误当成代码问题。5.2 模拟断线验证告警从产生到恢复的完整链路交付前最后要验证告警逻辑。可以临时用防火墙丢弃一台测试机的ICMP包观察系统是否在3次检测后生成离线告警再解除丢包看连续2次成功是否自动恢复。常见做法是# 模拟设备离线5分钟操作完成后必须解除 iptables -A INPUT -s 192.168.10.20 -p icmp -j DROP sleep 300 iptables -D INPUT -s 192.168.10.20 -p icmp -j DROP该命令在网管机与测试设备之间做定向丢包不影响其他网络对象。测试期间要同时观察三处告警表是否只生成一条离线告警而不是刷屏页面上的告警列表是否在10分钟内自动抑制重复记录解除丢包后告警状态有没有改回“已恢复”。如果测试设备是支持SNMP的交换机还可以用改管理口状态的方式验证接口告警但这类操作有真实业务风险只建议放在变更窗口执行。等这套验证全部通过再打开说明文档按步骤跑一遍数据库文档中的连接池参数和建表脚本都核对无误整个交付物才算站得住。本文还有配套的精品资源点击获取