news 2026/10/19 5:49:40

滑动窗口协议C语言实现:计网实验答辩级源码解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
滑动窗口协议C语言实现:计网实验答辩级源码解析

简介:北京邮电大学计算机网络课程模拟数据链路层滑动窗口协议的实验源码与文档包,面向计网课程学生、准备期末大作业或课程设计的高校开发者;资源围绕数据链路层的可靠传输核心,演示滑动窗口、回退N帧、选择性重传等机制,适合有一定C语言基础、希望对照实现链路层协议的读者。压缩包共18个文件,以C源码和头文件为主体,覆盖选择性重传、回退N帧、改进GBN等不同协议版本,同时包含CRC32校验、参数解析、链路层封装实现,附带Visual Studio工程、README说明与结果截图,整体仅71KB,目录划分明确,便于按需查阅。源码均已在本地编译通过,评审分达95分以上,难度适中,且经助教老师审定;读者可直接运行观察运行截图,也可在此基础上改造窗口大小、帧格式或校验策略。目前已有173人学习,适合快速上手北邮计网实验要求,作为C语言网络编程与协议设计的参考模板。

1. 计网实验里的滑动窗口协议:一份能拿去答辩的 C 语言实现长什么样

在计网实验里,“模拟数据链路层的滑动窗口协议”是典型的期末大作业题目:看着简单,动手就崩。很多人第一反应是写个脚本模拟丢包重传,但课程设计最终要求的是协议状态机的正确性,而不是黑盒应用。这份资源提供的是 C 语言实现,源码能在本地编译运行,评审分达到 95 分以上,覆盖停等、回退 N、选择重传三种模式,并附文档说明。适合谁用?正在做计网实验或期末大作业的学生,以及想把滑动窗口状态机一次捋清楚的从业者。下面按方案落地的顺序,把这套源码的设计思路、关键实现和验收方法一次讲清楚。

2. 需求分析与技术选型:三种协议模式要覆盖到什么程度

2.1 从题目要求里先拆出三个硬指标

一般这类课设题目不会直接说“实现滑动窗口”,而是给几个隐含条件。第一个硬指标是模拟数据链路层的帧收发,不能靠 TCP socket 绕过去;第二个是至少实现两种协议并能切换,最好能对比停等、回退 N 和选择重传;第三个是运行过程要能观察窗口滑动、超时重传和 CRC 校验,不是只在控制台打印“发送成功”。

很多同学拿到题目就找轮子,找到能运行的源码先庆祝,结果答辩被问“协议模式怎么切换”就愣住,因为代码里没有策略入口,协议逻辑全写在 main 函数里。这套资源的 protocol.c 承担的就是策略入口,selective.c、gobackn.c、gbn_improve.c 各实现一种策略,protocol.h 暴露统一接口。从文件结构能看出它不是堆三个 main,而是把公共链路层逻辑抽出来了,这样设计才支撑得住三个硬指标。

2.2 为什么用 C 而不是 Python 模拟

一轮课设做下来,我最想强调的选型结论是:滑动窗口实验用 C 语言写,比用 Python 写脚本更容易拿高分。评分点集中在“协议是否正确、代码是否分层、参数是否可配置”,C 的结构体、指针和位操作能把帧格式、缓冲区、状态机直接映射到代码里,老师查代码时一眼能看到链路层的影子。Python 写起来确实快,但列表和字典会掩盖缓冲区管理和字节序细节,答辩时老师挑个细节追问就容易露馅。

更重要的是,这里选择的是进程内模拟信道而不是真实 socket。链路层实验只关心序号、确认、窗口和超时,这些逻辑不需要经过真实网卡;真实网络会引入丢包、乱序、延迟抖动,结果不可复现。进程内模拟把丢包率设为参数,固定随机种子后,同一参数跑出来的结果完全一致,截图和日志能对上,答辩自然有说服力。

2.3 命令行参数和验收演示的对应关系

getopt.c 和 getopt.h 的存在说明这套代码支持命令行参数运行。通常支持的参数包括协议模式、窗口大小、丢包率和日志级别。

参数作用验收演示怎么用
-p/--protocol切换 stop_and_wait、gobackn、selective、gbn_improve现场切换三种协议,对比重传策略
-w/--window设置发送窗口大小,停等协议固定为 1改窗口大小看窗口滑动差异
-l/--loss_rate模拟信道丢包率,0~100设 0、10、30 跑三组,观察重传
-v/--verbose是否输出详细日志演示时开,截图时留关键日志

这个参数设计不只是在演示时好看,它直接对应评审表里的“可配置性”。老师现场要“把丢包率调到 30 再看看”,如果你要改代码重编译才能做到,当场就败了。用 getopt 解析还有个好处:参数错误时有 usage 提示,配合 README 里的说明,助教不需要看代码就知道怎么启动。我一般会检查 main 函数开头是否对参数做了校验,例如窗口大小不能为 0、丢包率必须在 0 到 100 之间,这些边界值提前挡掉,演示时才不会出现除零或数组越界。

2.4 源码分层:从文件依赖关系读代码

拿到源码不要从第一行开始读。先看 protocol.h 和 datalink.h 的接口声明,再看 protocol.c 的调用关系,最后才看 selective.c 和 gobackn.c。datalink.c 是主入口,负责初始化信道、解析参数、循环驱动发送;protocol.c 是协议分发;各协议文件负责窗口状态机;crc32.c 和 lprintf.c 是工具层。用工程的话说,这是“主流程—策略层—工具层”三层划分。

原资源里有 datalink.vcxproj 和 datalink.sln,说明在 VS 里可以直接打开编译;Linux 下用 gcc 编这些 C 文件时,记得把 getopt.c 一起编,因为不同平台 getopt 的行为有差异,使用项目自带的 getopt 能避免环境不一致。README.md 一般会写清楚编译命令和参数示例,我在拿到资源后第一件事是照 README 跑一遍默认参数,确认能复现 results.png 里的输出,再开始读代码。

2.5 窗口大小与序号空间的设计边界

在滑动窗口协议里,序号空间必须足够区分“新帧”和“重传的旧帧”,通常要求序号空间大于最大发送窗口的两倍。这套资源里 frame_t 的 seq 字段是 uint8_t,序号范围 0~255,实验中的窗口大小一般取 4 或 8,完全够用。但代码里必须对 seq 取模,否则窗口设到 16 后接收端会分不清新帧和重传帧。

selective.c 里接收缓存数组按窗口大小分配,索引不能直接用 seq 当数组下标,应该先判断 seq 是否落在接收窗口内,再对缓存大小取模后写入。这个边界我重点检查过,因为很多自己写的代码窗口小的时候正常,窗口一调大就偶发越界。对应到实际工程里,序号位数、窗口大小、缓冲区大小三者要一起设计,不是随便选一个窗口大小就能跑。

2.6 链路层模拟和 TCP 重传的区别

还有一个容易混的点:滑动窗口协议不是 TCP。TCP 的滑动窗口按字节流编号,有拥塞控制、RTT 估算和快速重传;这个实验的窗口按帧序号编号,只解决可靠传输,不解决拥塞。所以把 TCP 的重传经验直接套到链路层代码里会出问题,比如 TCP 收到三个重复 ACK 会快速重传,GBN 收到重复 ACK 只是确认接收端还缺哪一帧,不应该触发重传。

链路层协议里超时重传的触发条件就是超时器,不在 ACK 数量上做文章。代码里 start_timer 和 stop_timer 的粒度是“序号”而不是“连接”,这也是和 TCP 最直观的区别。理解这一点,答辩时被问到“超时时间怎么定”才不会拿 RTT 估算公式硬套,链路层实验里通常就是固定超时值,或者按模拟信道的延迟加一个余量。

2.7 协议实现里的四个状态变量

在阅读 selective.c 和 gobackn.c 之前,建议先记住四个状态变量:base(发送窗口底部)、next_seq(下一个待发序号)、expect_seq(接收端期望的下一帧序号)、window_size(发送窗口上限)。在代码里它们的命名可能各不相同,但角色是一样的。datalink.c 负责初始化这些变量,protocol.c 可能在切换协议时重置它们。

我见过一种低年级写法:把 base 和 next_seq 定义成全局变量,三种协议到处改,结果切模式后状态残留。正确做法是每种协议一个上下文结构体,切换协议时独立初始化。这个资源如果按文件分工看,selective.c 和 gobackn.c 内部应该各自维护上下文,不共享全局窗口变量。答辩被问“为什么 GBN 切到 SR 不会串状态”,回答“各自有独立 ctx”就比解释“我直接改了全局变量”稳得多。

3. 总体设计与核心实现:从帧结构到窗口状态机的完整流程

3.1 帧结构:先定义清楚链路上传什么

链路层协议的第一步永远是帧结构。这套源码的 protocol.h 里定义了 frame_t,核心字段包括帧类型 type、序号 seq、确认号 ack、长度 len、CRC 校验值 crc 和载荷 payload。为什么 seq 和 ack 都占 8 bit?因为模拟实验的帧序号空间不需要很大,8 bit 覆盖 256 个序号,而且能让帧结构紧凑,更接近真实链路层设计。

typedef struct frame_t { uint8_t type; /* 0-DATA, 1-ACK, 2-NAK */ uint8_t seq; /* 帧序号,按窗口空间取模 */ uint8_t ack; /* 期望收到的下一帧序号 */ uint16_t len; /* payload 长度 */ uint32_t crc; /* 整帧 CRC32 校验值 */ char payload[256]; } frame_t;

设计说明:ACK 帧不需要载荷,len 可以传 0,接收端只解析 type 和 ack;DATA 帧的 crc 覆盖的是前面所有字节,包括 type、seq、ack、len 和 payload,不能只对 payload 算 CRC,否则帧头部被篡改时校验不出问题。发送端填充帧时,seq 要用发送序号对序号空间取模,ack 字段填的是“期望收到的下一帧序号”,不是“刚刚收到的序号”,这两个字段的语义最容易写反。

3.2 CRC32:查表法和逐位法的取舍

crc32.c 实现的是标准 CRC32。这里给一个可以直接跑通的逐位版函数,逻辑是标准多项式 0xEDB88320 的反射形式:

uint32_t crc32(const uint8_t *data, size_t len) { uint32_t crc = 0xFFFFFFFF; for (size_t i = 0; i < len; i++) { crc ^= data[i]; for (int j = 0; j < 8; j++) { if (crc & 1) crc = (crc >> 1) ^ 0xEDB88320; else crc >>= 1; } } return crc ^ 0xFFFFFFFF; }

参数说明:初值 0xFFFFFFFF 和末尾异或 0xFFFFFFFF 是标准 CRC32 的两个关键点,少一个都会导致和常见校验工具结果不一致。逐位版看起来简洁,但每字节要做 8 次循环,如果要模拟大量帧,性能会拖后腿。所以 crc32.c 里通常用查表法:初始化时生成 256 个表项,运行时每字节一次查表加三次异或。查表法代码看着长,但效率高几倍,这是工程里更常见的做法。需要注意,查表法生成表时用的多项式方向和逐位法要一致,否则两边算出来对不上。

3.3 发送窗口状态机:累计确认和超时重传

滑动窗口协议的核心不在一帧怎么发,而在窗口何时向前滑动。发送端有三个关键变量:base(窗口底部)、next_seq(下一个待发序号)、window_size(窗口上限)。收到 ACK 之后,如果 ack 大于 base,说明 base 到 ack-1 的所有帧都被确认,base 就可以推进。这个“累计确认”是回退 N 协议最重要的语义,也是唯一能和选择重传区分开的行为。

void sender_on_ack(sender_t *s, uint8_t ack) { if (ack >= s->base + 1 && ack <= s->next_seq) { s->base = ack; log_window("slide", s->base, s->next_seq); } }

参数说明:在回退 N 中,ack 字段表示“期望收到的下一帧序号”,所以 ack == base + 1 表示序号为 base 的那一帧已经收到,窗口底部前移一格。收到重复 ACK 时 ack 不会大于当前 base,直接忽略。这比“每收到一个 ACK 就推进一格”的做法更贴近真实协议,也避免乱序 ACK 导致窗口反复回退。

超时处理要区分 GBN 和 SR:GBN 超时后重传 base 到 next_seq-1 的所有帧,SR 只重传超时的那一帧。这里的重传范围差异直接决定了两种协议的信道利用率差异。GBN 实现简单,但窗口越大浪费越大;SR 需要接收端缓存乱序帧,还要处理 NAK,代码复杂度上了一个台阶。gbn_improve.c 通常就是在 GBN 框架上做“只重传丢失帧”的优化,相当于在实现复杂度和信道效率之间取折中。

3.4 接收端逻辑:GBN 不缓存,SR 才缓存

接收端的实现比发送端更容易写错。GBN 的接收窗口大小固定为 1,只接受 seq == expect_seq 的帧;如果收到乱序帧,正确的做法是丢弃并重新发送一个 ACK,告诉发送端我还期待哪一帧。很多实现把 GBN 写成了 SR:收到乱序帧先缓存,等前面的帧补齐后再一起上送,虽然没有明显 bug,但已经不是回退 N 协议了。答辩时老师会问“你这个缓存区是干什么的”,如果 GBN 也回答“缓存乱序帧”,基本就暴露了概念不清。

选择重传的接收端则必须有窗口缓存,数组大小至少等于发送窗口的两倍,索引用 seq 对缓存大小取模。收到帧后先判断 seq 是否落在当前接收窗口内,不在就丢弃;在窗口内就放入缓存并检查能否把连续的数据段上送。上送后推进 expect_seq,同时发送 ACK。这段逻辑在每个协议实现里单独维护,不放进公共的 datalink.c,目的就是让三种策略互不干扰。

int sr_receive(sr_ctx_t *ctx, frame_t *f) { int idx = f->seq % ctx->buf_size; if (!in_receive_window(ctx, f->seq)) return 0; ctx->cache[idx] = *f; /* 尝试把从 expect_seq 开始的连续帧上送 */ while (ctx->cache[ctx->expect_seq % ctx->buf_size].seq == ctx->expect_seq) { deliver(ctx, &ctx->cache[ctx->expect_seq % ctx->buf_size]); ctx->expect_seq++; } send_ack(ctx, ctx->expect_seq); return 1; }

这段代码里的 in_receive_window 检查必须放在取模之前,否则越界访问可能发生在窗口判断之前。上送循环用 expect_seq 对缓存大小取模作为下标,保证缓冲区是循环使用的。这里体现了 SR 和 GBN 最大的不同:接收端有自己的窗口和缓存,发送端不能假设“没收到 ACK 就一定丢帧”。

3.5 模拟信道:丢包率怎么控制才能演示不翻车

datalink.c 里的模拟信道负责在发送端和接收端之间注入丢包。最简单的方式是 rand() % 100 < loss_rate 就丢弃。但注意 rand() 默认随机种子是固定的,想要结果可复现可以用固定种子,想要每次不同可以用当前时间做种子。课设演示建议用固定种子:第一次跑出重传事件后记下参数,答辩时按相同参数重跑,结果完全一样,不会出现“刚刚还能跑,现在怎么不重传了”的翻车现场。

int channel_send(channel_t *ch, frame_t *f) { if (rand() % 100 < ch->loss_rate) { lprintf("LOSS seq=%d\n", f->seq); return 0; } lprintf("TX seq=%d type=%d\n", f->seq, f->type); deliver_frame(ch, f); return 1; }

这里丢包率是百分制,loss_rate 设为 10 时大约每 10 帧丢 1 帧。日志里 LOSS 行要保留,它是说明“这帧没到达接收端”的直接证据;如果只打印 TX 不打印 LOSS,看起来就像发送端根本没发这帧。窗口滑动和超时重传都依赖日志来证明,所以 lprintf 的输出格式值得在 README 里专门说明。

3.6 三种协议如何共用同一个主流程

很多自己写的滑动窗口代码最大的问题是三种协议各写各的主函数,switch 里复制粘贴。这套资源把公共流程抽成 datalink.c 里的统一调度。主循环大致是:先处理到达的 ACK 或数据帧,再检查定时器,最后填满发送窗口。协议策略层只实现三个回调:init、handle_frame、timeout。这样 GBN 和 SR 的差异都被封装在各自文件里,datalink.c 不用知道窗口细节。

static void run_protocol(protocol_ctx_t *ctx, channel_t *ch) { while (!ctx->done) { handle_channel_events(ctx, ch); /* 接收 ACK 或数据帧 */ update_timers(ctx); /* 检查超时,触发重传 */ fill_window(ctx, ch); /* 发送窗口内新帧 */ } }

三种协议的差异集中在 handle_channel_events 和 fill_window 内部:GBN 的 fill_window 在超时后重传整个窗口;SR 的重传由定时器单独触发;gbn_improve 则在损失一帧时只补那一帧。主循环不变,后续加新协议只需要新增文件并实现回调。答辩被问“能不能加一个新协议”时,能回答“新增一个文件实现三个函数”的同学,和现场改代码的同学,分数是完全不同的。

3.7 对照实验:同一丢包率下三种协议的重传次数差异

演示环节最有说服力的不是单跑一个协议,而是同一丢包率下三种协议的横向对比。设丢包率 10%、窗口 8、发送 100 帧,停等协议几乎每个丢包都要停等一个 RTT,回退 N 会把窗口内后续帧全部重传,选择重传只重传丢失帧。把三组日志里的重传次数整理成表格,比口说“SR 效率高”直观得多。

协议丢包率 10% 的重传行为日志特征
停等每次丢包后等待超时,重发同一帧同一 seq 重复 TX
GBN超时后重传窗口内所有帧连续几帧重复 TX
SR超时只重传丢失的那一帧单个 seq 重复 TX,且伴随缓存滑动日志

这个对照表可以直接作为实验报告“结果分析”章节的三行结论。gbn_improve 的对比还可以加一列:它比 GBN 少重传窗口内已知收到的帧,但不需要 SR 那样的接收缓存,介于两者之间。答辩时能背出这个差异,比会默写定义更能让老师相信你调过代码。

4. 常见问题与避坑:滑动窗口实验最容易翻车的 5 个点

这一章写给已经能编译运行、但一改参数就翻车的同学。以下五条是我在这个项目里见到最多的现场,按概率排序。每条我都会给一个快速定位方式:先看日志有没有某种特征,再对照原因,最后改代码。比直接告诉你“某个函数应该怎么写”更实用,因为很多同学的代码经过自己改换后,行号已经和原始版本对不上了,只有从现象反推才能定位。

4.1 窗口只往前挪一格,吞吐量上不去

现象:日志里 ACK 一直在增加,发送端也确实收到了,但发送窗口的 base 始终慢半拍,窗口利用率只有一半。用 4 窗口跑 100 帧,重传次数看起来很少,但总用时比预期长很多。

原因:ACK 被处理成“单个确认”而不是“累计确认”。典型的错误写法是收到一个 ACK 就把 base 加 1,或者用位图记录“第 n 帧收到”,结果丢失中间某一帧时,后面的 ACK 都推不动窗口。滑动窗口协议的 ACK 字段是“期望收到的下一帧序号”,它天然携带了累计信息:ack = 4 代表 0~3 都到了。

解决:统一走 sender_on_ack 那套逻辑,先判断 ack 是否在 [base+1, next_seq] 范围内,再直接把 base 更新为 ack。范围外的 ACK 全部忽略。改完以后可以设丢包率 0 跑一遍,观察日志里 base 是不是按 1、2、3 连续推进。定位方式也很简单:打开日志,数一数收到 ACK 后 base 是否连续增加;如果 ACK 和 base 总是差 1,多半是确认语义没统一。

4.2 GBN 模式没有超时重传日志,乱序帧却全收到了

现象:选择 GBN 时,把丢包率调到 20%,运行完发现日志里都是 RX,超时重传一次都没发生,最后统计结果里重传次数却是 0。评审老师一看就怀疑协议没写对。

原因:接收端把乱序帧缓存起来了。GBN 的接收窗口大小固定为 1,只接受 seq == expect_seq 的帧;乱序帧应该立刻丢弃并重发 ACK,让发送端感知到缺失,从而触发超时重传。如果接收端像 SR 一样缓存乱序帧,GBN 发送端就一直收不到超时信号,逻辑上悄悄变成了别的协议。

解决:在 GBN 的 receive_frame 里,先判断 seq 是否等于 expect_seq,不等就直接丢弃并发送 ACK(expect_seq),不要触碰任何缓存数组。日志里应该能看到 DISCARD seq=... 的记录,这样才有论据说“接收端按 GBN 语义处理了乱序帧”。定位方式:把丢包率调到 20%,跑完看有没有重传日志;如果有 RX 却没有重传,接收端大概率缓存了乱序帧。

4.3 CRC32 工具算的和程序算的对不上

现象:帧在信道里没有丢包,但接收端每次都说校验失败。把同一个缓冲区拿去网上工具算,也能算出另一个结果,两边永远对不上。

原因:标准 CRC32 的初值是 0xFFFFFFFF,算完后再异或 0xFFFFFFFF。常见抄代码只把算法主体抄了,没带上 init 和 final xor;或者查表法的表项生成方向不对,用的多项式是 0x04C11DB7 而不是反射的 0xEDB88320。还有一个隐蔽点:发送端给 crc 字段赋值后再对整帧做 CRC,接收端如果对包含 crc 字段的整帧再做一次 CRC,这种“余数法”的判定结果和“先算后比较”只能二选一,不要混用。

解决:先用字符串 "123456789" 验证 crc32 函数,正确结果应该是 0xCBF43926。对上了再检查发送端计算 CRC 时是否覆盖了 type、seq、ack、len、payload 全部字段,接收端校验范围要完全一致。定位方式:单独写个十行测试函数,把缓冲区打印出来,对比两边实际参与 CRC 的字节数,一眼就能看出差异。

4.4 窗口从 4 调到 16 后偶发越界

现象:窗口大小 4 一切正常,改成 16 后开始偶发崩溃,或者日志里出现一些不应该存在的帧序号。把缓存数组长度加大后又不崩了,但不知道为什么要加大。

原因:SR 接收缓存数组通常按窗口大小分配,而帧序号是循环使用的。如果直接用 seq 当数组下标,seq 增长到超过数组长度就会越界。这是典型的小窗口能跑、大窗口现原形的 bug。

解决:访问缓存前先判断 seq 是否落在当前接收窗口,落在外面的直接丢弃;落在窗口内的,用 seq % buf_size 作为数组下标。窗口大小、序号空间、缓冲区大小三者的关系在设计阶段就要定好,别等越界了才想起来取模。定位方式:窗口调到 16,打开调试器在缓存赋值处打断点,观察 seq 是不是已经越过数组上界。

4.5 演示日志堆成黑匣子,答不出丢没丢包

现象:答辩演示时终端疯狂滚动,截一张能说明重传过程的图都难。助教问“你这帧到底丢没丢”,只能指着屏幕说“刚刚好像有一行 LOSS 闪过去了”。

原因:所有输出都走裸 printf,没有时间戳,没有 TX/RX/LOSS 标记,也没有日志级别控制。printf 的输出在管道重定向时还可能受缓冲影响,和实际事件顺序不一致,进一步增加了解释成本。

解决:统一用 lprintf 输出,每条日志带毫秒时间戳、方向标记和帧类型。演示前用相同随机种子跑通一次,日志重定向到文本,截图保留“LOSS → TX 重传 → ACK”这样连贯的三行,比十屏滚动日志有说服力得多。定位方式:日志重定向到文本文件后,搜索 LOSS 行是否和 TX 行顺序一致;顺序乱了就是缓冲问题,顺序没乱但肉眼找不到,就是日志格式缺标记。

5. 验收与答辩:把 95 分的评审点拆成一张自查表

交之前,我会按这张表走一遍,每一行都对应评审老师可能翻的代码位置。

自查项怎么做常见扣分点
源码编译VS 打开 datalink.sln 直接生成,或 gcc 编全部 C 文件答辩现场说“在我电脑上能跑”
参数切换用 -p、-w、-l 三个参数分别跑三种协议协议模式写在宏里,改一个值要重编译
帧格式完整protocol.h 里 type、seq、ack、crc 都有只传结构体,不做 CRC
窗口滑动可见日志能看到 base 从 0 推进到末尾只有发送统计没有窗口变化
协议语义正确GBN 丢弃乱序帧,SR 缓存乱序帧把 GBN 写成 SR 的缓存逻辑
结果可复现固定随机种子,同一参数结果一致每次运行重传次数都不同

演示顺序我习惯固定成三遍:停等协议丢包率 0,证明基本收发没问题;GBN 丢包率 10%,展示窗口回退和批量重传;SR 同丢包率,展示只重传单帧。三组日志放在三张截图里,老师问差异时直接指着重传数量回答。答辩被问到代码时,按“状态变量变化 + 函数调用链 + 异常情况分支”三点讲,不要只背函数名。这套资源里自带文档说明和 results.png,直接按这个流程补截图,就能形成一份完整验收材料。

最后说一个我的习惯:从那以后我每次碰协议模拟实验,都强制自己在写代码前先用表格把 sequence 推演一遍,再动手。这个习惯帮我少踩了很多坑,希望也能帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/19 5:48:53

Spring Boot外部接口加密实战:混合加密与签名防篡改方案

1. 接口加密这件事&#xff0c;到底在防什么先说一个真实场景&#xff1a;你负责的 Spring Boot 项目上线后&#xff0c;第三方系统要通过 HTTP 接口拉数据、推数据。你想着内网有防火墙&#xff0c;外网有 HTTPS 证书&#xff0c;数据在传输过程中是密文&#xff0c;应该够安全…

作者头像 李华
网站建设 2026/10/19 5:48:15

Canary绕过全解析:栈溢出、信息泄漏与利用链实战

1. 为什么安全研究者都在研究怎么“绕 canary”1.1 一场授权渗透演练带出来的问题前一阵做某次授权边界设备评估的时候&#xff0c;我在目标二进制里同时找到了格式化字符串和栈溢出。看到溢出点那一刻心里其实没多少波动&#xff0c;因为按老思路&#xff0c;栈溢出直接盖返回…

作者头像 李华
网站建设 2026/10/19 5:46:47

机器人训练数据精筛:从规模至上到质量优先的多维评估框架

说实话&#xff0c;当我第一次看到"让机器人像美食家一样精挑细选训练数据"这个表述时&#xff0c;我是有点意外的。意外不是因为想法多新奇&#xff0c;而是在机器人学习这个圈子里&#xff0c;大家已经卷了很久的数据规模&#xff0c;突然有人说要开始挑食了。过去…

作者头像 李华
网站建设 2026/10/19 5:45:47

MySQL入门到进阶:数据库设计、SQL优化与避坑指南

很多人学 MySQL&#xff0c;都是从“安装”和“基础操作”开始的&#xff1a;官网下个安装包&#xff0c;装完敲几条 select、建一张表&#xff0c;就觉得自己入门了。但真正进项目写业务代码时才发现&#xff0c;字符集为什么乱码、索引为什么没生效、为什么别人同样一条 SQL …

作者头像 李华
网站建设 2026/10/19 5:43:32

物理AI时代来临:开发者如何抓住机器人智能化的新机遇?

每年CES&#xff0c;我都会把演讲全程看一遍再写速记。往年大家最关心的是显卡参数、游戏性能&#xff0c;但到了今年&#xff0c;风向明显变了——从展前预热到各厂家的动作来看&#xff0c;物理AI才是真正的主角。我说的物理AI&#xff0c;不是又一个概念炒作。上一轮生成式A…

作者头像 李华
网站建设 2026/10/19 5:43:32

同步压缩时频图+多尺度CNN,构建WTMCNN轴承故障诊断

前阵子做旋转机械状态监测项目&#xff0c;用振动加速度信号做轴承故障分类。一开始图省事&#xff0c;直接拿短时傅里叶变换出来的频谱图喂给CNN&#xff0c;测试集准确率卡在90%上下怎么都上不去。后来同事提醒了一句&#xff0c;把输入从普通时频图换成同步压缩时频图&#…

作者头像 李华