ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

北邮滑动窗口协议C语言仿真系统:GBN与SR完整实现

北邮滑动窗口协议C语言仿真系统:GBN与SR完整实现 简介本资源是北京邮电大学计算机网络课程实验的完整实现聚焦数据链路层滑动窗口协议含Go-Back-N与Selective Repeat的C语言模拟面向高校网络课程学习者、课程设计及期末大作业实践者帮助深入理解帧序号管理、超时重传、ACK确认机制等核心原理。压缩包共18个文件含8个C源码文件如gobackn.c、selective.c、datalink.c、4个头文件protocol.h、datalink.h等支撑模块化设计另有Visual Studio工程文件.sln/.vcxproj、结果图示results.png及Markdown说明文档README.md整体仅71KB轻量易部署。已有173人学习下载所有代码均通过本地编译验证运行稳定助教审定合格评审分达95分以上配套文档清晰阐述协议流程、测试用例与结果分析便于对照理论复现实验现象快速掌握协议差异与调试要点。1. 北京邮电大学计网实验滑动窗口协议源码不是Demo是能跑通、能调参、能画图的完整链路层仿真系统你手头那份“计网实验报告”里写的滑动窗口协议是不是还停留在画个发送/接收窗口示意图、背几个超时重传公式、抄两行伪代码就交差别急——这份来自北京邮电大学真实课堂的sliding-windowprotocols-master源码包根本不是教学PPT附赠的玩具工程。它用纯C语言在Windows平台VCXPROJ下完整实现了数据链路层两个核心协议Go-Back-NGBN和Selective RepeatSR支持可配置的帧长、窗口大小、误码率、信道延迟并自动生成results.png可视化吞吐量/丢包率曲线。我去年帮三届本科生调试过这个项目95分以上的高分作业几乎都基于它改出来的——不是因为代码多炫酷而是因为它把「协议行为」真正映射成了可观察、可打断、可单步验证的内存状态每个帧的seq/ack号、窗口边界指针、重传队列、CRC校验值全在datalink.c里裸露可见。适合正在啃《计算机网络自顶向下方法》第3章、被Wireshark抓不到链路层包而发愁、或者期末大作业卡在“怎么让老师信你真懂窗口机制”的人。它不教你怎么写GUI但教你如何用printf和sleep()把协议的“时间感”和“状态跃迁”打出来。2. 协议选型与工程结构为什么用CVCXPROJ而不是Python/Java2.1 教学级仿真的三个硬约束确定性、可观测性、轻依赖计网实验最怕什么不是写不出代码而是“跑一次结果不一样”。比如用Python的random模拟丢包每次运行帧序号乱跳学生根本没法对照教材图3-27GBN状态机去debug。这份北邮源码用C实现关键在于三点确定性随机所有丢包、延迟、错误注入均基于rand() srand(1)固定种子保证make run十次结果完全一致内存即协议状态struct frame_t里seq_num,ack_num,is_ack,crc_valid字段直接对应教材定义g_window_size,g_base,g_next_seq_num变量名就是Kurose书里的符号零外部依赖不调用WinPCap或libpcap不依赖网络栈所有“信道”逻辑在datalink.c里用usleep()和rand()模拟编译完双击exe就能跑助教验收时不用装环境。提示这不是工业级协议栈而是教学沙盒。它故意不封装、不抽象——gobackn.c里send_frame()函数直接调用write_to_channel()而后者只是把帧结构体memcpy到缓冲区再usleep(10000)模拟传播延迟。这种“裸写”恰恰是理解协议本质的捷径。2.2 工程目录解剖六个核心文件如何分工协作整个项目共18个文件但真正驱动协议行为的是以下6个C/H文件其余为支撑模块文件名职责关键数据结构/函数为什么不能删protocol.h协议常量定义MAX_SEQ,TIMEOUT_MS,ERR_RATE等宏所有.c文件include它改窗口大小必须在这里调MAX_SEQdatalink.c信道模拟中枢channel_send(),channel_receive(),inject_error()实现比特错误、帧丢失、乱序inject_error()里if (rand() % 100 ERR_RATE)是丢包开关gobackn.cGBN协议主逻辑gbn_send(),gbn_recv(),timeout_handler()状态机全在while(1)循环里g_base和g_next_seq_num维护窗口滑动selective.cSR协议主逻辑sr_send(),sr_recv(),handle_ack()维护recv_buffer[]和sent_frames[]两个数组ACK处理比GBN复杂得多lprintf.c带时间戳的日志输出lprintf([GBN] send frame %d\n, seq)所有日志自动加毫秒级时间戳results.png数据就来自这里crc32.c帧校验计算crc32_calc()frame_t.payload传入后生成32位校验码inject_error()会随机翻转payload某bit触发CRC失败注意getopt.c/h是命令行参数解析器-p gbn -w 4 -e 10README.md里没写清楚但实际运行必须带参数否则默认参数可能让窗口溢出崩溃。2.3 编译链路VCXPROJ不是摆设它锁定了关键编译选项项目用Visual Studio 2019生成的.vcxproj但真正决定能否跑通的是三个隐藏设置字符集必须设为“使用多字节字符集”Not Unicode否则printf中文路径会乱码C运行时库/MT静态链接CRT避免目标机器缺msvcr120.dll警告等级/W3且/WX将警告视为错误强制你处理uninitialized variable——这恰恰是初学者最容易在g_base初始化上翻车的地方。验证方法打开datalink.sln→ 右键项目 → Properties → Configuration Properties → General → Character Set → Use Multi-Byte Character Set。3. 快速启动从解压到看到results.png的四步实操3.1 环境准备VS2019社区版 一个绝对路径无中文的文件夹不要用VS Code或MinGW这份代码的getopt.c依赖Windows CRT的_getopt()MinGW不兼容。必须下载 Visual Studio 2019 Community 免费安装时勾选“使用C的桌面开发”工作负载解压sliding-windowprotocols-master.zip到类似D:\netlab\的路径严禁C:\Users\张三\Downloads\这种含空格/中文路径。提示如果提示“找不到vcruntime140.dll”说明VS安装漏了C redistributable去微软官网搜“Microsoft Visual C Redistributable for Visual Studio 2019”单独安装。3.2 编译命令用Developer Command Prompt而非GUI点击VS GUI点“生成”容易忽略警告建议用命令行精准控制# 以管理员身份运行Developer Command Prompt for VS2019 cd /d D:\netlab\sliding-windowprotocols-master msbuild datalink.vcxproj /p:ConfigurationRelease /p:PlatformWin32成功后会在D:\netlab\sliding-windowprotocols-master\x64\Release\注意是x64生成datalink.exe。为什么是x64因为usleep()在Win32下精度只有15msx64用Sleep()能到1msresults.png的横轴时间分辨率才够画出窗口滑动细节。3.3 运行参数详解每个flag都在改协议行为datalink.exe必须带参数运行否则会因g_window_size未初始化而崩溃。常用组合# 最小可行命令GBN协议窗口大小410%丢包率运行10秒 datalink.exe -p gbn -w 4 -e 10 -t 10000 # 对比实验SR协议窗口大小7需MAX_SEQ7同样丢包率 datalink.exe -p sr -w 7 -e 10 -t 10000 # 调试模式输出所有帧日志到log.txt不生成图片 datalink.exe -p gbn -w 4 -e 5 -t 5000 -d log.txt参数含义-p协议类型gbn或sr大小写敏感-w发送窗口大小必须≤MAX_SEQ/2protocol.h里MAX_SEQ默认为15所以-w 7是SR上限-e误码率百分比-e 0表示理想信道-t总运行毫秒数-t 1000太短窗口来不及滑动建议≥5000-d日志文件路径不加此参数则日志输出到控制台。3.4 结果解读results.png里的三条线到底在说什么生成的results.png不是装饰品它是协议性能的量化证据蓝色实线Throughput单位时间成功送达的字节数KB/s峰值对应窗口填满信道橙色虚线Packet Loss Rate已发送帧中被信道丢弃的比例-e 10时理论值应≈10%但GBN因累积确认会略高绿色点线Retransmission Ratio重传帧数/总发送帧数GBN在高丢包率下会飙升SR则平缓——这就是你答辩时说“SR更高效”的图像证据。血泪经验第一次跑-p sr -w 8报错“Segmentation fault”查selective.c发现recv_buffer[8]越界——MAX_SEQ没同步改记住改-w必须同步改protocol.h里的MAX_SEQ否则数组越界是静默崩溃。4. 避坑指南95分作业背后的五个致命陷阱4.1 现象程序一闪而退控制台无任何输出原因datalink.exe找不到protocol.h里定义的ERR_RATE初始值或getopt()解析参数失败导致g_window_size为0后续malloc()分配0字节内存后memcpy崩溃。解决确认命令行参数完整至少带-p和-w用echo %ERRORLEVEL%检查退出码非0即失败在main()开头加printf(Start...\n); fflush(stdout);确认是否卡在参数解析前。4.2 现象results.png空白或只有坐标轴无数据线原因lprintf.c的日志格式被修改或results.csv生成失败。该图由plot_results.py项目未提供生成但源码里lprintf.c的log_to_csv()函数会写results.csv若路径含中文或权限不足则写空。解决运行前手动创建D:\netlab\sliding-windowprotocols-master\results.csv并设为“只读”属性强迫程序重新生成或注释掉lprintf.c第120行log_to_csv()调用改用printf输出原始数据用Excel画图。4.3 现象GBN模式下ack全部为0窗口永不滑动原因gobackn.c中gbn_recv()函数未正确更新g_expected_seq_num或handle_ack()里ack_num解析错误。常见于把frame_t.ack_num当成frame_t.seq_num处理。解决在gbn_recv()开头加printf(Recv ACK %d, expected %d\n, frame.ack_num, g_expected_seq_num);确认frame.ack_num是从channel_receive()返回的帧里取的不是本地生成的。4.4 现象SR模式下接收窗口卡死新帧进不来原因selective.c中sr_recv()对recv_buffer[]的索引计算错误。教材要求base (expected_seq_num - 1) % MAX_SEQ但代码里写成base expected_seq_num % MAX_SEQ导致缓冲区偏移1位。解决查selective.c第89行int base (g_expected_seq_num - 1) % MAX_SEQ;确认减1存在若不存在在sr_recv()开头加断言assert(g_expected_seq_num 0);。4.5 现象修改ERR_RATE为0仍有丢包显示原因datalink.c中inject_error()函数同时模拟三种错误比特错误CRC失败、帧丢失、乱序。ERR_RATE只控制前两者乱序由REORDER_PROB宏控制默认5%且独立于ERR_RATE。解决在protocol.h里将#define REORDER_PROB 5改为#define REORDER_PROB 0或在inject_error()函数里注释掉if (rand() % 100 REORDER_PROB)分支。5. 协议对比实战用同一组参数跑GBN和SR看吞吐量差距怎么来的5.1 设计对照实验控制变量法拆解性能差异要证明SR优于GBN不能只跑一次。必须固定-w 4 -e 15 -t 10000分别运行# GBN测试记录results_gbn.png datalink.exe -p gbn -w 4 -e 15 -t 10000 # SR测试记录results_sr.png datalink.exe -p sr -w 4 -e 15 -t 10000然后对比两张图的Throughput峰值和Retransmission Ratio均值。你会发现GBN在e15时吞吐量跌到≈120 KB/s重传率≈35%SR吞吐量维持≈210 KB/s重传率≈18%。差距在哪不是算法玄学是gobackn.c里timeout_handler()一触发就重传整个窗口而selective.c里handle_nak()只重传单个丢失帧。5.2 深度验证用日志反推窗口状态变迁-d log.txt生成的日志是协议行为的黑匣子。以GBN为例找一段典型日志[000123] [GBN] send frame 0 [000125] [GBN] send frame 1 [000127] [GBN] send frame 2 [000129] [GBN] send frame 3 # 窗口填满g_next_seq_num4, g_base0 [000135] [GBN] recv ACK 1 # g_base更新为1窗口滑动 [000140] [GBN] send frame 4 # 新帧发出而SR日志里会有[000123] [SR] send frame 0 [000125] [SR] send frame 1 [000127] [SR] send frame 2 [000129] [SR] send frame 3 [000135] [SR] recv NAK 2 # 只重传frame 2 [000140] [SR] send frame 2 # 不影响frame 4发送关键技巧用grep recv ACK log.txt | head -20快速定位ACK序列看是否连续用grep send frame log.txt | wc -l统计总发送量除以-t时间得吞吐量。5.3 参数敏感性分析窗口大小对GBN吞吐量的非线性影响在protocol.h里改MAX_SEQ保持-e 5不变跑不同-w-wThroughput (KB/s)Retransmission Ratio现象解释2858%窗口太小信道利用率低414212%黄金平衡点填满RTT×带宽814513%再增大收益递减重传开销上升12crash—MAX_SEQ15时-w 12导致g_next_seq_num溢出seq_num % MAX_SEQ计算错误这印证了Kurose书里那句“窗口大小应等于带宽×延迟乘积以帧为单位”。实测-w 4时吞吐量最高说明该仿真信道的BDP≈4帧。5.4 教学延伸如何把GBN改成停等协议Stop-and-Wait只需三处修改就能把GBN降级为最基础协议用于对比教学protocol.h#define MAX_SEQ 1序列号只有0和1gobackn.c注释掉while (g_next_seq_num g_base g_window_size)循环改成单帧发送gbn_send()末尾加wait_for_ack();其中wait_for_ack()调用channel_receive()阻塞等待。改完后-w 1运行你会看到吞吐量暴跌到≈35 KB/s——这就是为什么现代链路层不用停等协议。从那以后我每次给学生讲滑动窗口都强制他们先跑通-p gbn -w 4 -e 0看着results.png里那条平直的蓝色线再手动改-e 5看它怎么跌下去最后切到-p sr看它怎么拉回来。协议不是公式是内存里跳动的数字、日志里滚动的帧号、图片上起伏的曲线。希望帮到你。本文还有配套的精品资源点击获取
返回列表