基于 FPGA 的主机 IP 自动配置方案设计
目录前言1.DHCP协议1.1、 DHCP 报文格式1.2、 DHCP Options选项字段1.3DHCP 的核心DORA 交互流程1. Discover发现阶段2. Offer提供阶段3. Request请求阶段4. Acknowledge确认阶段1.4、 租约维护Lease2. 基于 FPGA 的主机 IP 自动配置方案设计2.1 方案一嵌入式 DHCP 服务器硬件逻辑实现 (DHCP Server Logic)代码如下Discover和Request的代码offer 和 Acknowledge阶段的代码核心区别siaddr vs Server Identifier (Option 54)在Verilog 代码中如何实现建议配置表代码调试调试成功现象调试经验2.2 方案二IPv4 Link-Local (最简单的纯硬件方案)2.2.1. 核心原理RFC 3927 标准2.2.2. FPGA 端的实现步骤第一步固化 IP 和 MAC 地址第二步必须实现 ARP 响应关键第三步简单的 UDP 监听/发送3. 为什么大家都说它有“潜规则”拓展1DHCP请求和确认阶段的必要性1. 协议的“盲目性” (Standardization)2. 为什么物理上“一根线”也可能有多个服务器3. 在 Request 报文中电脑是如何“挑人”的对你 FPGA 实现的启示总结拓展二电脑端的行为双重机制并行DHCP Link-Local1. 抓包证据分析2. 为什么电脑会“坚持不懈”拓展三UDP的端口选取1. 端口的三大分类2. 为什么你的 DHCP 必须用 67 和 683. FPGA 开发中的自由度 调试总结前言针对科研探测设备与上位机直连的通信需求本文提出了基于 FPGA 的两种主机 IP 自动配置方案DHCP 协议与 IPv4 链路本地地址Link-Local Address。该设计有效规避了传统静态 IP 手动配置的局限性显著提升了系统部署的灵活性与自动化水平。1.DHCP协议DHCPDynamic Host Configuration Protocol动态主机配置协议是应用层协议旨在为网络中的主机自动分配 IP 地址、子网掩码、默认网关以及 DNS 服务器。其在以太网帧的位置如下其中各层协议的组成如下1.1、 DHCP 报文格式在 FPGA 中手写 DHCP你需要关注的是这个巨大的 UDP 载荷通常固定为300 字节以上。字段名称长度 (Bytes)描述FPGA 实现要点Message Type (op)11Request, 2Reply作为 Server你发送时该位恒为0x02Hardware Type1以太网通常为0x01恒定值Hardware Length1MAC 地址长度恒为0x06恒定值Hops1跳数通常为0x00恒定值Transaction ID (xid)4关键随机传输 ID你发出的 Offer 必须拷贝 Discover 里的这个 IDSeconds2客户端开始请求后的秒数通常设为0x0000Flags2广播标志位0x8000表示要求服务端广播回复Client IP (ciaddr)4客户端当前 IP初始请求时为0.0.0.0Your IP (yiaddr)4分配给电脑的 IP这是你告诉电脑“给你这个 IP”的地方Server IP (siaddr)4DHCP 服务器 IP填入你给 FPGA 设定的 IPClient MAC (chaddr)16客户端 MAC 地址前 6 字节填入电脑的 MAC后 10 字节补 0Magic Cookie4固定为0x63, 0x82, 0x53, 0x63协议识别标志不可写错Options变长协议扩展选项见下表1.2、 DHCP Options选项字段Options 是 DHCP 的精华采用Type-Length-Value (TLV)格式。在 FPGA 中你需要手动拼接这些字节。常见的 OptionsOption 53 (Message Type)长度 1 字节。1代表 Discover2代表 Offer3代表 Request5代表 Ack。Option 51 (Lease Time)长度 4 字节。告知电脑 IP 能用多久例如3600秒。Option 1 (Subnet Mask)长度 4 字节。子网掩码如255.255.255.0。Option 54 (Server Identifier)长度 4 字节。服务器自己的 IP 地址。Option 255 (End)长度 1 字节。固定为0xFF代表 Options 结束。1.3DHCP 的核心DORA 交互流程DHCP 建立在UDP之上服务端监听67端口客户端监听68端口。其核心交互被称为DORA流程。1.Discover发现阶段客户端服务端全网广播。电脑客户端插上网线后不知道谁是 DHCP 服务器于是发送一个目的 IP 为255.255.255.255的广播包寻找网络中的服务器。字段层级关键字段值 (Hex/描述)硬件处理要点MAC 层目的 MACFF:FF:FF:FF:FF:FF广播帧。IP 层源 / 目的 IP0.0.0.0/255.255.255.255此时电脑还没 IP。UDP 层源 / 目的端口68/67电脑客户端到服务端。DHCP 层op0x01代表这是一个请求 (Request)。xid0x12345678(随机)FPGA 必须存下这个 ID后续回包要用。chaddr电脑的 MAC 地址FPGA 必须存下这个 MAC作为回复的目标。Option 530x35 0x01 0x01消息类型Discover。2.Offer提供阶段服务端客户端单播或广播。DHCP 服务器收到请求后从自己的地址池中选出一个未分配的 IP例如192.168.1.100并携带租期、掩码等信息回发给客户端。字段层级关键字段值 (Hex/描述)硬件处理要点MAC 层目的 MAC电脑的 MAC如果设置了广播位也可以发FF...FF。IP 层源 / 目的 IPFPGA IP /255.255.255.255此时电脑还没 IP只能发广播或根据 MAC 寻找。DHCP 层op0x02代表这是一个回复 (Reply)。xid同 Discover 的xid匹配事务否则电脑会丢弃。yiaddr192.168.1.100这是你打算分给电脑的 IP。Option 530x35 0x01 0x02消息类型Offer。Option 10x01 0x04 FF FF FF 00告诉电脑子网掩码是255.255.255.0。3.Request请求阶段客户端服务端全网广播。电脑可能收到多个服务器的 Offer它会选择其中一个并再次广播“我接受了来自服务器 A 分配的192.168.1.100其他的 Offer 我拒绝了。”注意这里依然用广播是为了告诉其他服务器它们可以收回之前提供的 IP。字段层级关键字段值 (Hex/描述)硬件处理要点MAC 层目的 MACFF:FF:FF:FF:FF:FF全网广播。DHCP 层xid同上事务 ID 保持不变。Option 530x35 0x01 0x03消息类型Request。Option 50192.168.1.100电脑明确说“我要刚才那个 IP”。Option 54FPGA 的 IP 地址核心这是电脑选中的服务器 ID。如果不是你的 IP说明它选了别人。对这部分的理解在拓展1。4.Acknowledge确认阶段服务端客户端单播或广播。服务器正式确认该 IP 租借给客户端并告知最后的配置细节。字段层级关键字段值 (Hex/描述)硬件处理要点IP 层源 / 目的 IPFPGA IP /255.255.255.255最后的广播确认。DHCP 层op0x02回复。yiaddr192.168.1.100再次确认分配的 IP。Option 530x35 0x01 0x05消息类型ACK。Option 510x33 0x04 0x00 0x00 0x8C A0租期例如设置为 36000 秒。1.4、 租约维护LeaseDHCP 分配的 IP 不是永久的而是“租”给电脑的。T1 定时器当租期达到50%时电脑会向 FPGA 发送单播 Request尝试续约。T2 定时器当租期达到87.5%时电脑会发送广播 Request 寻找任何可用的服务器。对 FPGA 的简化建议在你的 VLF 信号处理应用中为了简化逻辑你可以给出一个极长的租期例如 7 天甚至忽略 T1/T2 的续约逻辑。只要网线没断电脑通常不会主动放弃 IP。2. 基于 FPGA 的主机 IP 自动配置方案设计在科研探测设备与上位机直连的场景下为了摆脱手动配置静态 IP 的繁琐过程本系统设计了硬件协议栈级的自动寻址逻辑。2.1 方案一嵌入式 DHCP 服务器硬件逻辑实现 (DHCP Server Logic)该方案通过在 FPGA 内部构建一个轻量级的应用层 DHCP 服务器状态机主动为主机分配指定网段的 IP 地址。交互过程如1.3小结所示。对应的 DHCP Server 逻辑如下UDP 解析只要收到目标端口为67的 UDP 包。状态机跳转收到Discover发送Offer把你的固定 IP 段扔过去。收到Request发送Ack。报文拼接技巧由于大部分报文字节是固定的你可以把一个完整的 Offer 包约 342 字节包含 Ethernet/IP/UDP 头存入 FPGA 的ROM中。发送时只需实时动态替换以下几个关键点以太网帧的目的 MAC。DHCP 报文里的xidTransaction ID。重新计算 IP 和 UDP 的Checksum校验和。代码如下Discover和Request的代码default_nettype none module dhcp_server_request( input wire clk, input wire rst_n, // UDP RX Interface input wire udp_rx_busy, input wire [15:0] udp_r_dst_port, input wire [7:0] udp_r_data, input wire udp_r_data_valid, // User Interface output reg [31:0] out_xid, output reg [47:0] out_chaddr, output reg out_is_discover, output reg out_is_request, output reg out_valid ); localparam S_IDLE 4h1; localparam S_PAYLOAD 4h2; localparam S_OPTIONS 4h4; localparam S_DONE 4h8; reg [3:0] state, next_state; reg [15:0] cnt; // 1. 状态寄存器 (Sequential) always (posedge clk) begin if (!rst_n) state S_IDLE; else state next_state; end // 2. 下一状态逻辑 (Combinational) always (*) begin case (state) S_IDLE: next_state (udp_rx_busy udp_r_dst_port 16d67) ? S_PAYLOAD : S_IDLE;//不需要判断op,因为FPGA作为服务端 S_PAYLOAD: next_state (udp_r_data_valid cnt 16d239) ? S_OPTIONS : S_PAYLOAD; S_OPTIONS: next_state (udp_r_data_valid udp_r_data 8h35) ? S_DONE : (~udp_rx_busy ? S_IDLE : S_OPTIONS); S_DONE: next_state S_IDLE; default: next_state S_IDLE; endcase end // 3. 输出逻辑与寄存器更新 (Sequential) always (posedge clk) begin case (state) S_IDLE: begin cnt 16d0; out_valid 1b0; end S_PAYLOAD: begin if (udp_r_data_valid) begin cnt cnt 1b1; // 提取 xid (Offset 4-7) if (cnt 16d4) out_xid[31:24] udp_r_data; if (cnt 16d5) out_xid[23:16] udp_r_data; if (cnt 16d6) out_xid[15:8] udp_r_data; if (cnt 16d7) out_xid[7:0] udp_r_data; // 提取 Client MAC (Offset 28-33) if (cnt 16d28 cnt 16d33) out_chaddr {out_chaddr[39:0], udp_r_data}; end end S_OPTIONS: begin if (udp_r_data_valid) begin // 记录 Option 53 之后的一个字节内容 out_is_discover (udp_r_data 8h01); out_is_request (udp_r_data 8h03); end end S_DONE: begin out_valid 1b1; // 触发发送模块脉冲 end endcase end endmodule需要记录xid、电脑的MAC地址以及判断请求的类型即可。offer 和 Acknowledge阶段的代码default_nettype none module dhcp_server_reply( input wire clk, input wire rst_n, // UDP TX Interface output reg udp_tx_req, input wire udp_tx_busy, output wire [15:0] udp_t_data_len, input wire udp_t_data_ready, output reg udp_t_data_valid, output reg [7:0] udp_t_data, // Control Interface input wire [31:0] in_xid, input wire [47:0] in_chaddr, input wire in_is_discover, input wire in_is_request, input wire start ); localparam S_IDLE 4h1; localparam S_START 4h2; localparam S_SEND 4h4; localparam S_WAIT 4h8; reg [3:0] state, next_state; reg [15:0] cnt; assign udp_t_data_len 16d300; // 固定包长度 // 1. 状态寄存器 always (posedge clk) begin if (!rst_n) state S_IDLE; else state next_state; end // 2. 下一状态逻辑 always (*) begin case (state) S_IDLE: next_state start ? S_START : S_IDLE; S_START: next_state udp_tx_busy ? S_SEND : S_START; S_SEND: next_state (udp_t_data_ready cnt udp_t_data_len - 1) ? S_WAIT : S_SEND; S_WAIT: next_state ~udp_tx_busy ? S_IDLE : S_WAIT; default: next_state S_IDLE; endcase end // 3. 输出逻辑 always (posedge clk) begin case (state) S_IDLE: begin udp_tx_req 1b0; udp_t_data_valid 1b0; cnt 16d0; end S_START: begin udp_tx_req 1b1; end S_SEND: begin udp_tx_req 1b0; if (udp_t_data_ready) begin udp_t_data_valid 1b1; cnt cnt 1b1; // DHCP 字节拼接逻辑 case (cnt) 16d0: udp_t_data 8h02; // op: Reply 16d1: udp_t_data 8h01; // htype: Ethernet 16d2: udp_t_data 8h06; // hlen // Transaction ID 16d4: udp_t_data in_xid[31:24]; 16d5: udp_t_data in_xid[23:16]; 16d6: udp_t_data in_xid[15:8]; 16d7: udp_t_data in_xid[7:0]; // Your IP (yiaddr): 10.0.0.203 16d16: udp_t_data 8d10; 16d17: udp_t_data 8d0; 16d18: udp_t_data 8d0; 16d19: udp_t_data 8d203; // Client MAC (chaddr) 16d28: udp_t_data in_chaddr[47:40]; 16d29: udp_t_data in_chaddr[39:32]; 16d30: udp_t_data in_chaddr[31:24]; 16d31: udp_t_data in_chaddr[23:16]; 16d32: udp_t_data in_chaddr[15:8]; 16d33: udp_t_data in_chaddr[7:0]; // Magic Cookie 16d236: udp_t_data 8h63; 16d237: udp_t_data 8h82; 16d238: udp_t_data 8h53; 16d239: udp_t_data 8h63; // Option 53: Offer(2) or ACK(5) 16d240: udp_t_data 8h35; 16d241: udp_t_data 8h01; 16d242: udp_t_data in_is_discover ? 8h02 : 8h05; // End Option 16d243: udp_t_data 8hFF; default: udp_t_data 8h00; endcase end end S_WAIT: udp_t_data_valid 1b0; endcase end endmodule提供和确认阶段需要向电脑提供应答op,硬件类型硬件长度xid(用的是电脑提供的)yiaddr(给电脑配置的IP地址)CHAddr(电脑的MAC地址)Magic Cookie固定字节Option 53: Offer(2) or ACK(5)。其他默认为0即可。对应的解释如下在 FPGA DHCP Server 实现中siaddr下一个服务器 IP 地址完全可以“省略”即填充为0.0.0.0也可以设置为 FPGA 自己的 IP 地址。对于直连电脑并分配 IP 的简单场景这个字段通常是不需要的。核心区别siaddrvsServer Identifier(Option 54)在 DHCP 协议中这两个 IP 地址字段的功能完全不同你只需要保证Option 54正确即可siaddr(Next Server IP Address)位于 DHCP 固定首部。它仅在客户端需要进行网络启动如 PXE 启动并从另一台服务器如 TFTP 服务器获取启动文件时才使用。如果你的 FPGA 只是给电脑分个 IP将其设为32h0000_0000是最标准、最省事的做法。Option 54(Server Identifier)位于 DHCP 选项区Options。这个字段必须填写 FPGA 自己的 IP 地址。它是电脑用来识别到底是哪台服务器给它发了 Offer 的关键标志。在Verilog 代码中如何实现参考你提供的代码片段yiaddr(Your IP Address)你已经实现在了偏移16d16到16d19的位置这是分给电脑的 IP。siaddr(Next Server IP Address)它紧随其后对应计数器cnt为16d20到16d23的位置。目前的实现由于你的代码中default分支将数据设为了8h00这意味着siaddr已经被你默认“省略”为了0.0.0.0。这对你目前的 VLF 信号探测项目来说是完全正确的。建议配置表如果你想让报文看起来更“专业”一点可以参考下表进行填充字段对应 cnt (Hex/Dec)建议填充值作用yiaddr16d16~16d1910.0.0.203给电脑用的地址siaddr16d20~16d230.0.0.0可省略填零Option 5416d243附近需计算FPGA 自己的 IP告诉电脑“我是谁”温馨提示除非你打算让这台电脑通过网线从你的 FPGA 里“远程启动”一个操作系统这对于 VLF 系统来说确实有点炫技了否则没必要折腾siaddr。代码调试在 Windows、Linux 或 macOS 系统中可以通过命令行或图形界面强制触发 DHCP 客户端重新发送请求。这在调试 FPGA 的 DHCP Server 逻辑时非常有用因为你不需要反复拔插网线。我使用的是 Windows 环境可以使用以下命令重新获取 IP发送 DHCP Discoveripconfig /renew这是最关键的一步。执行该命令后Windows 会立即发送DHCP Discover广播包。如果FPGA 逻辑正确且硬件通路已通就能在 Wireshark 中看到响应过程。调试成功现象依次执行四个交互过程并获取里面的IP。调试经验1状态机需要正确idx,交互阶段的类型需要判断正确2UDP的源端口和目的端口是固定的需要注意。调试过程的记录见资源“DHCP调试过程.doc”2.2 方案二IPv4 Link-Local (最简单的纯硬件方案)IPv4 Link-Local链路本地地址通常被称为Auto-IP或APIPAAutomatic Private IP Addressing。在 Windows 系统中当你看到网卡显示“未识别的网络”并分配了一个169.254.x.x的 IP 时就是它在起作用。对于 FPGA 开发者来说这是实现“零协议成本”通信的最快路径。以下是该方案的深层运作机制和实现细节2.2.1. 核心原理RFC 3927 标准当一个网络设备比如你的电脑配置为“自动获取 IP”但物理链路接通后一段时间内没有收到任何DHCP Offer报文时它会认为网络中没有 DHCP 服务器。为了不让通信完全中断它会根据 RFC 3927 协议从 169.254.1.0 到 169.254.254.255 的地址池中随机挑选一个 IP。冲突检测电脑选定 IP 后会发出一个ARP Probe探测如果没有收到回应说明这个 IP 没人用它就正式启用该 IP。子网掩码固定为 255.255.0.0。2.2.2. FPGA 端的实现步骤在 FPGA 中你不需要写任何复杂的自动协商逻辑只需要“伪装”成一个已经在该网段内的静态设备。第一步固化 IP 和 MAC 地址在你的 Verilog 代码UDP/IP 协议栈模块中直接硬编码以下参数FPGA IP:169.254.1.10(建议选一个简单的避免冲突)。FPGA MAC:00:0A:35:00:01:02(自定义确保唯一即可)。Subnet Mask:255.255.0.0。第二步必须实现 ARP 响应关键这是很多同学实验失败的原因。即使你给 FPGA 设了 IP电脑在发送 UDP 数据包之前依然会发一个 ARP 请求问“谁是169.254.1.10”逻辑实现当 FPGA 收到以太网帧类型为0x0806(ARP) 且目标 IP 匹配时立即构造一个 ARP Reply 包把 FPGA 的 MAC 地址告诉电脑。只有 ARP 通了电脑的网卡驱动才会把上层 UDP 数据包通过物理层发出来。第三步简单的 UDP 监听/发送实现一个最基础的 UDP 模块监听特定端口如8080并处理来自电脑的数据流。3. 为什么大家都说它有“潜规则”虽然它实现起来最简单但有几个工程上的坑需要你提前知道现象原因影响启动慢Windows 默认会花30-60 秒疯狂寻找 DHCP Server。插上网线后你需要盯着任务栏直到那个“小圆圈”变成“黄色感叹号”或“未识别的网络”通信才真正开启。IP 不固定电脑端的 IP 是随机生成的例如这次是.12.34下次是.56.78。如果你的 FPGA 需要主动给电脑发数据你不能在代码里写死电脑的 IP。路由受限该地址无法通过路由器进入外网。仅限于点对点直连或交换机组网。该方法的确会自动配置一个IP地址但需要将FPGA的地址也设置为169.254.x.x才能通信。拓展1DHCP请求和确认阶段的必要性这是一个非常敏锐的观察在你的 FPGA 直连电脑点对点场景下物理上确实只有一台“服务器”但DHCP 协议作为一种通用标准它的设计初衷是处理复杂的局域网环境。要理解为什么要“多此一举”地广播我们可以从以下三个维度来看1. 协议的“盲目性” (Standardization)你的电脑作为 DHCP 客户端在发送Request报文时它的操作系统协议栈Windows/Linux并不知道网线的另一头是一个简单的 FPGA还是一个连接着数十台服务器的交换机。统一流程为了保证在任何网络环境下都能正常工作电脑必须严格遵守 RFC 标准。标准规定 Request 必须是广播这样可以确保被选中的服务器知道客户接受了它的 Offer。落选的服务器知道客户拒绝了它的 Offer从而立即释放掉那个被占用的临时 IP。2. 为什么物理上“一根线”也可能有多个服务器虽然你现在是直连但在实际工程应用中这根线可能接入了物理交换机交换机上可能挂载了多个开启了 DHCP 服务的设备。虚拟网桥/虚拟机如果你的电脑开启了 VMware 或 Hyper-V电脑内部可能会运行多个虚拟 DHCP 服务它们都会通过这根网线争抢分配 IP。多径冗余在工业或深空探测的地面站网络中为了可靠性通常会有主、备两台 DHCP 服务器同时运行。3. 在 Request 报文中电脑是如何“挑人”的既然是广播大家都能收到。那么 FPGA 怎么知道电脑是选了自己还是选了别人呢这取决于 DHCP Request 报文内部的一个关键字段Option 54 (Server Identifier)。如果电脑接受了 FPGA 的 Offer它会在 Option 54 填入FPGA 的 IP 地址。FPGA 的逻辑处理收到广播的 Request。检查 Option 54。如果是自己的 IP发送Ack确认。如果不是自己的 IP放弃回到IDLE说明电脑选了别人。对你 FPGA 实现的启示在纯 Verilog 实现时这个机制其实简化了你的设计而不是增加了难度无需关心目标 MAC由于电脑发出的 Request 是广播包目的 MAC 为FF:FF:FF:FF:FF:FF你的 FPGA 逻辑层不需要识别 MAC 地址就能直接抓到这个包进行解析。“懒人”实现技巧在你的点对点实验中既然确定只有 FPGA 一个服务器你可以甚至不去校验 Option 54。只要收到 Request 包就默认电脑选的是你直接回发 Ack 即可。冲突规避如果未来你的设备要接入复杂的实验室网络记得在状态机里加上对 Option 54 的校验防止 FPGA 错误地截获了电脑给实验室路由器的请求。总结广播 Request 就像是在一个喧闹的房间里大喊“A 先生我用你给我的那个号码了” 这样 A 先生FPGA可以确认而原本也想给你号码的 B 先生、C 先生听到后就会默默地把号码收回去给别人用。拓展二电脑端的行为双重机制并行DHCP Link-Local电脑在自动配置了169.254.x.x地址后仍然会持续发送 DHCP 请求。从Wireshark 抓包图中可以清楚地观察到这一行为1. 抓包证据分析现状确认你的电脑已经由于 DHCP 超时而启用了Auto-IP (APIPA)机制给自己分配了169.254.8.89这个地址见下图中的ipconfig结果。持续请求在抓包记录的第 27 行你可以看到一条DHCP Discover报文其源 IP 依然为0.0.0.0。这证明了即使电脑有了临时 IP它仍然在不断“寻找”真正的 DHCP 服务器。2. 为什么电脑会“坚持不懈”临时性与局限性169.254.x.x只是一个链路本地地址它只能在直连的小范围内通信无法访问外网或跨网段。后台重试机制操作系统的网络服务会保持 DHCP 客户端后台运行。它会定期发送广播通常是每隔几秒或几十秒一旦你的 FPGA 响应了请求并成功分配了 IP如你代码中设置的10.0.0.203电脑会立刻丢弃169.254.x.x地址并切换到正式 IP。拓展三UDP的端口选取在普通应用开发中UDP端口号选择可以有很大的自由度但在实现标准协议如 DHCP时端口是绝对不能随意取的。端口号的范围是。根据国际标准IANA它们被划分为三个“阶级”了解这些规则对你调试 FPGA 协议栈至关重要。1. 端口的三大分类范围类别说明常见例子知名端口 (Well-known)预留给标准服务不可随意占用。DHCP (67/68)、DNS (53)、HTTP (80)注册端口 (Registered)用于用户自定义的应用或特定软件。你之前工程用的8001动态端口 (Dynamic)操作系统随机分配给客户端临时使用的。浏览器访问网页时分配的随机端口2. 为什么你的 DHCP 必须用 67 和 68这就好比收音机如果广播电台在 90.0MHz 发射信号你的收音机必须调到 90.0MHz 才能听到。服务端FPGA必须监听 67 端口电脑发出的Discover报文是广播包它会敲响网络中所有设备 67 号端口的大门。如果你的 FPGA 没在这个端口“守着”包就丢了。客户端电脑必须监听 68 端口电脑在发包时告诉网络“我在 68 号端口等回信”。因此你的 FPGA 发送Offer时目的端口必须填 68。遇到的问题在你之前的抓包 中端口变成了0。在网络协议中端口 0 是一个保留值通常代表“无效”或“未指定”。电脑的防火墙和协议栈一看到端口是 0会认为这是一个非法数据包直接过滤掉。3. FPGA 开发中的自由度虽然标准协议很死板但在后续回传VLF 探测数据时你是完全自由的自定义协议你可以像之前的工程一样定义源端口为 8001目的端口为电脑上的上位机监听端口比如 8002。避坑指南虽然可以选之间的任何数字但尽量避开 3389 (远程桌面)、443 (HTTPS) 等常用端口防止和电脑上的其他软件“撞车”。 调试总结对于 DHCP Server 调试请死死记住这一组配对FPGA 发包时源端口 67目的端口 68。FPGA 收包时只处理目的端口为67的 UDP 包。只要这一组数字填对了Wireshark 就会立刻把你的包从绿色的“UDP”识别成蓝色的“DHCP”。以上就是本次笔记的内容。