
简介这份基于SDN的园区网络检测项目源码与配套文档面向计算机相关专业学生、教师及企业在职人员可用于课程设计、毕业设计或项目初期演示。资源围绕软件定义网络的园区场景提供完整可运行的检测系统涵盖前后端代码、构建脚本及环境说明。压缩包共621个文件包含264个Java后端文件、95个Vue前端组件、78个JavaScript脚本、87个SVG图标、13个Velocity模板及多个配置文件便于理解模块化开发与测试流程。整体大小约1.96MB轻量易部署目录结构清晰。目前已有154人学习下载具有一定参考价值。除源码外还附带若依环境使用手册、运行与打包脚本及数据库SQL文件读者可参照说明快速启动项目也可在此基础上扩展功能或作为论文撰写的实验支撑。代码经过测试运行成功适合初学进阶与实际演练。1. 基于SDN的园区网络检测系统一次从控制器到管理后台的完整落地做园区网运维的人多少都有过这种体验核心交换机上一条广播报文异常增多全网终端开始卡顿可你拿着命令行逐台设备登进去看像在黑匣子里摸象。SDN园区网络检测系统的思路是把这个黑匣子打开——由控制器统一拿交换机的实时状态端口流量、链路通断、异常报文全部汇聚到一个管理平台上展示和告警。这份资源正好覆盖了这条完整链路控制器侧检测逻辑、若依框架搭的业务后台、前端可视化页面以及配套的启动脚本和环境手册。适合拿它做毕设、课设也适合刚接触SDN的运维人员把「控制器 管理平台」这条链路完整跑通理解数据面和控制面到底是怎么协作的。2. 系统架构与关键选型RYU控制器加若依管理后台这条链路怎么分工2.1 园区网络检测为什么需要SDN先解决可见性问题传统园区网的检测手段主要靠SNMP轮询和端口镜像。SNMP轮询的问题在于粒度太粗5分钟一次采样的端口流量只能看趋势想判断某个终端是否在持续发广播帧几乎不可能。端口镜像又受限于镜像口的数量和交换机CPU处理能力在汇聚层设备上长期镜像不仅影响转发性能配置起来也麻烦。SDN的逻辑完全不同。OpenFlow协议把交换机的转发表抽象成流表控制器可以通过标准消息拿到每个交换机、每个端口的实时统计计数包括收发的字节数、报文数、错误包数还能主动下流表做定向检测。这意味着园区网络里所有接入交换机的状态都汇聚到控制器这一个集中点上检测策略也统一在控制器侧下发不再需要逐台登录设备配ACL或镜像。这套检测系统的定位很清楚面向中小型园区网络覆盖几十台OpenFlow交换机以内的规模。控制器侧用Python写的检测应用业务侧用若依框架做管理后台前端用Vue。这种组合在高校毕设和企业内部工具里很常见因为每个环节都有大量现成资料可以查遇到问题时不至于孤立无援。2.2 控制器与业务平台的分工数据面归RYU管理面归若依项目拆成两大部分控制器侧和业务侧。控制器侧是检测能力的核心通过OpenFlow协议和下层交换机交互拿到拓扑、端口统计、流表匹配计数然后把结果通过REST接口抛出去。业务侧基于若依框架主要做用户管理、权限控制、检测规则配置、告警记录展示和数据可视化。两侧通过HTTP接口通信控制器只负责检测和上报不存业务数据若依后台负责把检测结果落到MySQL里做持久化提供给前端查询。这种分离有个明显的好处检测逻辑升级不影响管理平台管理平台的权限模型也不干扰控制器的实时处理。我见过不少类似项目把检测逻辑直接写进管理后台的后端服务里短期内开发快但后面想换控制器或者加新的检测项改动范围马上失控。拆开了以后控制器API的返回格式稳定下来后台只管解析和展示维护边界非常清晰。项目里目录结构也是这么对应的。后端的批处理脚本run.bat对应若依后台启动run-web.bat对应前端Web服务package.bat和build.bat分别对应后端打包和前端构建。.env.development是前端的环境配置里面定义了后端API的地址.editorconfig统一代码风格。2.3 目录结构与bat脚本功能对照拿到源码之后先别急着双击脚本看清楚每个文件是干什么的再动手。这份资源里脚本的分工大致如下脚本文件对应模块实际作用ry.bat若依后台入口启动Spring Boot主程序的前置包装run.bat后端服务一次性启动编译并启动若依后台依赖本地的MySQL和Redisrun-web.bat前端Web服务启动Vue开发服务器默认端口通常为80或8080package.bat后端打包执行Maven clean package产出可部署的jar包build.bat前端构建执行npm run build产出dist静态资源clean.bat清理工作清掉target目录和node_modules缓存用于重新构建.env.development前端环境变量配置API请求地址、端口号、代理目标如果你之前跑过若依项目对这些脚本的套路不会陌生。run.bat本质上就是mvn spring-boot:run的包装run-web.bat是对npm run dev的包装。差别在于这个项目把两个服务拆开启动调试时互不干扰。我一般先启动后端观察日志输出到「启动成功」字样后再启动前端。提示bat脚本里的Java路径、Maven路径和Node路径是写死的如果你本机安装的路径不一致需要先改脚本里的绝对路径再执行。3. 环境搭建与一键启动从零把后台和检测服务跑起来3.1 前置环境版本要求这份资源本人测试时用的是Java 8、Maven 3.6、Node 14、MySQL 5.7和Redis 5.0。这组版本组合在若依社区里是验证过最多的不建议贸然把JDK升到17或Node升到20再跑除非你有把握处理依赖兼容问题。如果你本机已有更高版本我建议你在环境变量里把JAVA_HOME临时指向JDK 8再启动避免Spring Boot版本和Maven插件之间的冲突。MySQL和Redis必须提前装好并启动。若依后台启动后第一件事是连数据库做表结构和初始化数据校验连不上就直接退出。MySQL里需要提前创建好数据库编码用utf8mb4导入项目里提供的SQL文件。如果你下载的包里没有SQL文件可以在若依官网或项目文档里找对应版本的初始化脚本表结构是通用的。3.2 数据库初始化与后端启动先创建数据库并导入初始化SQL。打开命令行执行以下操作mysql -u root -p CREATE DATABASE ruoyi_sdn DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; exit; mysql -u root -p ruoyi_sdn /path/to/sql/ruoyi.sql导入完成后修改后端配置文件里的数据库连接信息。若依的配置在ruoyi-admin/src/main/resources/application-druid.yml里需要把URL、用户名和密码改成你本机的实际值spring: datasource: druid: master: url: jdbc:mysql://localhost:3306/ruoyi_sdn?useUnicodetruecharacterEncodingutf8zeroDateTimeBehaviorconvertToNulluseSSLfalseserverTimezoneAsia/Shanghai username: root password: your_password这里有三个参数容易踩坑。useSSLfalse是因为本地开发环境不需要SSL加密连接不带这个参数在高版本MySQL驱动下会报警告或报错。zeroDateTimeBehaviorconvertToNull处理的是数据库里0000-00-00类型的零日期值不设置的话查询记录时会抛异常。serverTimezoneAsia/Shanghai解决MySQL驱动8.x版本时区偏差问题不设置的话时间会被当成UTC时间和本地时间差8小时。修改完成后双击run.bat或者手动执行mvn clean package -Dmaven.test.skiptrue java -jar ruoyi-admin.jar看到以下日志输出时说明后台启动成功Started RuoYiApplication in 12.37 seconds启动过程中如果发现端口被占用注意看8080端口是谁在占用。Windows下可以用netstat -ano | findstr :8080查到PID后在任务管理器结束进程。3.3 前端启动与登录验证后端起来之后切到前端目录。这份资源里前端代码的目录名一般是ruoyi-ui或者web确认里面有package.json文件再执行npm install npm run dev如果npm install的速度很慢用淘宝镜像源npm config set registry https://registry.npmmirror.com前端启动成功后会输出一个访问地址默认是http://localhost:80如果你本机80端口被占用了打开ruoyi-ui/vue.config.js把devServer.port改成一个未占用的端口devServer: { port: 8081, proxy: { /api: { target: http://localhost:8080, changeOrigin: true } } }.proxy配置很关键。若依前端向后端发请求时统一走/api前缀代理把/api开头的请求转发到后端服务的8080端口。changeOrigin必须为true否则后端后端收到请求时Host头不匹配部分鉴权中间件会拒绝。登录页面看到后用默认账号admin和密码admin123登录能正常进入仪表盘说明整个后台链路已经通了。4. 核心检测逻辑实战链路发现、端口统计与异常告警4.1 控制器侧链路发现与端口状态监控检测系统的核心在控制器侧。项目里控制器检测应用会做两件基础事链路发现和端口状态采集。链路发现依赖LLDP协议控制器周期性下发LLDP探测报文交换机收到后上报给控制器控制器据此构建网络拓扑图。端口状态采集则是周期性地向每个交换机发送端口统计请求拿到每个端口的收发字节和报文数。控制器侧的关键代码逻辑大致如下用Python伪码表达这个检测循环from ryu.base import app_manager from ryu.controller import ofp_event from ryu.controller.handler import set_ev_cls from ryu.ofproto import ofproto_v1_3 from ryu.lib import dpid as dpid_lib class SdnLinkDetector(app_manager.RyuApp): OFP_VERSIONS [ofproto_v1_3.OFP_VERSION] def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.port_stats {} # (dpid, port_no) - (rx_bytes, tx_bytes) self.flow_stats {} # dpid - flow table entries set_ev_cls(ofp_event.EventOFPPortStatsReply, MAIN_DISPATCHER) def port_stats_reply_handler(self, ev): msg ev.msg dpid msg.datapath.id for stat in msg.body: key (dpid, stat.port_no) old self.port_stats.get(key) if old: rx_delta stat.rx_bytes - old[0] tx_delta stat.tx_bytes - old[1] # 计算当前周期的带宽利用率並上报 self._report_bandwidth(key, rx_delta, tx_delta) self.port_stats[key] (stat.rx_bytes, stat.tx_bytes)这段代码的核心是EventOFPPortStatsReply事件处理器。控制器周期性下发OFPFlowStatsRequest和OFPPortStatsRequest交换机回复后触发对应的事件。port_stats这个字典记录每个交换机端口的历史字节数新数据和上一次相减就得出采样周期内的增量字节数再除以采样间隔就能算出带宽利用率。set_ev_cls装饰器里的MAIN_DISPATCHER参数表示只在主交换阶段处理该事件这样避免在握手阶段收到不完整数据时误判。4.2 业务侧检测规则配置与告警记录落库控制器把检测结果上报后业务侧需要把「异常」这个概念落地成可配置的规则。若依后台的管理页面上你可以配置每个端口的带宽告警阈值、链路通断检测间隔、广播报文比例上限等参数。配置保存后写入MySQL后台的定时任务周期性地从控制器API拉取最新状态和阈值做比对。业务侧的告警判断核心逻辑如下这里以带宽突增检测为例public ListAlarmRecord checkBandwidthAlarm(ListPortStatVO stats, ListAlarmRule rules) { ListAlarmRecord alarms new ArrayList(); for (PortStatVO stat : stats) { for (AlarmRule rule : rules) { double ratio stat.getBandwidthUtilization(); if (ratio rule.getUpperThreshold() rule.getEnabled()) { AlarmRecord record new AlarmRecord(); record.setSwitchDpid(stat.getDpid()); record.setPortNo(stat.getPortNo()); record.setMetricType(BANDWIDTH); record.setCurrentValue(ratio); record.setThreshold(rule.getUpperThreshold()); record.setAlarmTime(new Date()); alarms.add(record); } } } return alarms; }这个方法的核心逻辑是两层遍历外层遍历控制器拉取到的所有端口状态内层遍历用户配置的告警规则。匹配到超过阈值的端口就生成一条告警记录。注意record里同时保存了当前值和阈值这样前端展示时能直接显示超了多少不用再回来查规则表。4.3 把检测数据变成可视化图表数据落到MySQL之后前端图表就是水到渠成的事。项目前端用ECharts渲染带宽趋势图后端提供对应的REST接口。前端请求/stat/bandwidthTrend?dpidxxxportNoyyy的参数按时间维度返回采样数据// 前端仪表盘组件中的核心请求逻辑 getBandwidthTrend(dpid, portNo) { return request({ url: /stat/bandwidthTrend, method: get, params: { dpid: dpid, portNo: portNo, startTime: this.startTime, endTime: this.endTime } }) }这段代码直接调用封装好的request实例baseURL在.env.development里配置为/api前缀。startTime和endTime是时间范围参数组件里默认拉最近24小时的数据。拿到的数据是「时间点带宽利用率」的序列直接用ECharts的line类型渲染即可。提示如果你发现图表数据有断点大概率是控制器在某几个采样周期内没有响应比如交换机CPU繁忙或控制器负载过高。先把采样间隔调大到30秒再观察比直接调大阈值更合理。5. 避坑指南从启动失败到检测不准的六个常见问题5.1 双击bat脚本闪退现象Windows下双击run.bat或ry.bat时窗口一闪就消失命令行什么都看不到。原因脚本里执行出错后直接exit没有pause暂停窗口。最常见的原因是JAVA_HOME没有指向JDK 8或者Maven路径不存在。解决打开命令行手动执行脚本文件并加上pause或者在bat的末尾自己加一行pause。也可以先执行java -version确认JDK版本是否正确再执行mvn -version确认Maven路径。就是不要盲改脚本。5.2 MySQL连接报Communications link failure现象后端启动时报com.mysql.cj.jdbc.exceptions.CommunicationsException提示无法连接数据库。原因MySQL服务没启动或者数据库名和配置里的库名不一致。也常见于MySQL做了密码策略强化但你的连接配置依旧用旧密码格式。解决先确认MySQL正在运行Windows下在服务管理器里查MySQL服务状态。再用命令行实际登录一次mysql -u root -p确认密码正确。最后检查application-druid.yml里的url里数据库名是否和CREATE DATABASE时一致。5.3 Redis未启动或端口不一致现象后台日志中出现Unable to connect to Redis或JedisConnectionException服务启动到一半就退出了。原因若依框架用Redis做会话缓存和验证码存储Redis没启动时Spring容器初始化会失败。解决启动Redis后再重启后端。如果你的Redis设置了密码还需要在application.yml里配置redis.password。注意若依默认情况不配密码也能连如果你本机Redis设置了requirepass不配置就永远连不上。5.4 前端页面能打开但控制器状态显示离线现象后台登录正常仪表盘能进去但拓扑图和交换机列表显示离线刷新也没变化。原因控制器应用没启动或者控制器REST接口的IP端口和后台配置的不一致。前端和后端是通的但后端到控制器的这条链路断了。解决先单独启动控制器应用确认控制器的REST服务监听在哪个端口再用浏览器直接访问控制器的健康检查接口看能否返回JSON。最后把若依后台里配置控制器地址的项改对。如果你在服务器上跑控制器注意防火墙要放行控制器API端口本机访问不经过防火墙但局域网访问会被拦。5.5 控制器能连上但检测数据始终为零现象控制器侧日志显示交换机已接入但后台统计的端口流量全是0图表是一条直线。原因采样周期和统计口径不一致。控制器侧可能把统计值放在某个私有字段里而后台解析时读的是标准OpenFlow字段两者对不上。也可以是交换机的流表没有生效流量没有命中任何流表项计数自然为零。解决先在控制器侧用命令行工具查看原始统计消息的完整内容确认rx_bytes字段里有实际数据增长。再检查交换机的流表项确认通配符规则存在保证流量至少命中一条默认转发规则。如果控制器打印出来的统计值有增长但后台接口返回0那就是JSON序列化和反序列化时字段名映射不对仔细对比两端代码里的字段定义。5.6 重复启动导致端口被占用现象第二次启动后端时报Web server failed to start. Port 8080 was already in use。原因上一次启动的后端进程没有完全退出Git Bash或者IDE里杀掉终端后Java进程还在后台运行。解决kill掉占用8080端口的进程。Windows下执行netstat -ano | findstr :8080查看PID然后taskkill /PID 进程号 /F。如果你用了IDE的停止按钮注意Java进程有时不会跟着终止需要在任务管理器里确认。6. 再进一步用定时任务把检测告警自动导出成日报检测系统跑通之后最实用的一项扩展是把每天的告警汇总成日报。若依框架自带Quartz定时任务模块在这个基础上做导出功能不用引入任何新框架。第一步在若依后台新增一张告警日报表字段包含日期、告警总数、带宽告警数、链路告警数、各交换机告警排名。第二步写一个定时任务类标注Component和Scheduled注解每天凌晨一点执行统计查询把昨天的告警数据按维度汇总后写入日报表。第三步做一个导出接口把日报表数据拼装成Excel文件返回给前端下载。核心的定时器代码如下Component public class AlarmDailyReportTask { private static final DateTimeFormatter FORMATTER DateTimeFormatter.ofPattern(yyyy-MM-dd); Autowired private AlarmRecordMapper alarmRecordMapper; Autowired private AlarmDailyReportMapper dailyReportMapper; Scheduled(cron 0 0 1 * * ?) public void generateYesterdayReport() { String yesterday LocalDate.now().minusDays(1).format(FORMATTER); ListAlarmRecord records alarmRecordMapper .selectListByDate(yesterday); if (records.isEmpty()) { return; } AlarmDailyReport report new AlarmDailyReport(); report.setReportDate(yesterday); report.setTotalCount(records.size()); report.setBandwidthCount((int) records.stream() .filter(r - BANDWIDTH.equals(r.getMetricType())).count()); report.setLinkCount((int) records.stream() .filter(r - LINK.equals(r.getMetricType())).count()); dailyReportMapper.insert(report); } }cron表达式0 0 1 * * ?表示每天凌晨1点执行。selectListByDate方法按日期精准匹配注意MySQL的DATETIME字段和Java时间字符串之间不能直接比你需要在SQL里加上DATE_FORMAT或CAST转换。搞定这个功能后你会意识到检测系统真正的价值不在于实时告警而在于数据沉淀。「昨天全网告警几次、哪个交换机占比最多」这种问题以前要翻日志凭记忆回答现在打开日报表一目了然。做这类系统我有个习惯每改一次控制器代码就要求自己重新跑一遍全链路回归——控制器起来、交换机模拟器接入、后台拉取状态、触发告警、写库、查询展示。这个过程强制走了一遍以后再大的改动都有底气。希望这个项目的源码加上这篇笔记能帮你把SDN园区网络检测从「看过概念」变成「跑得起来又改得动」也希望你在这个基础上做出自己的扩展。本文还有配套的精品资源点击获取