ARTICLE DETAIL

资讯详情

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

ARP协议获取局域网活动主机MAC地址的Winpcap实现解析

ARP协议获取局域网活动主机MAC地址的Winpcap实现解析 简介这是一份面向计算机网络课程设计的完整PDF方案适合高校计算机专业学生完成ARP协议相关实验、理解地址解析机制时参考也可用于广工等院校课程设计答辩前的查漏补缺。文档围绕使用ARP协议获取局域网内活动主机物理地址这一C程序设计目标依次讲解ARP工作原理、以太网与ARP帧结构、Winpcap发包收包流程并附有完整代码分析和运行结果截图可直接对照搭建Visual C开发环境并复现关键步骤。资源包共1个PDF文件约458KB内容聚焦、便于打印阅读目前已有169人学习浏览。通过这份材料读者可以系统掌握从构造ARP请求、发送广播帧、监听并解析应答到输出IP-MAC映射表的完整实现链路同时巩固IP与MAC地址映射、网卡工作模式等网络基础知识。1. ARP 协议取局域网活动主机物理地址的课设这个老题目为什么还值得拆计算机网络课设里有一道经典题使用 ARP 协议获取局域网内部活动主机物理地址的程序实现C 环境。题目看着简单真要交差却要过四关数据帧怎么定义才符合公共标准、Winpcap 怎么把帧发出去、响应帧怎么收怎么解析、结果怎么显示。这份 PDF 恰好把四关全走了一遍——它是一份完整课设报告含 ARP 协议原理梳理、数据帧结构定义、VC 工程代码、运行结果和心得总结代码部分还专门做了字节对齐和双线程处理。适合正在做类似课设的学生、想用 Winpcap 写局域网扫描小工具的人以及想快速回顾 ARP 协议原理和帧布局的工程师。我拆完的感觉是代码可以直接抄但字节序、内存对齐、混杂模式三处坑抄的时候要特别小心不然发出去的包没人理。2. ARP 帧结构与原理1428 字节的链路拼图2.1 以太网帧头与 ARP 报文每个字段都有固定偏移ARP 协议解决的是 IP 地址到物理地址的映射问题。物理层不认 IP 地址只认 MAC 地址所以 A 主机想和 D 主机通信必须先拿到 D 的 MAC。A 广播一个 ARP 请求局域网里所有在线主机都会收到但只有 IP 匹配的那台会回一个 ARP 响应把自己的 MAC 地址通报出来。A 收到响应后把 IP-MAC 对存进缓存后续通信直接查缓存这就是 ARP 高速缓存。原课设里扫描活动主机的思路本质就是批量发 ARP 请求然后等响应。帧的布局是整道题的地基。以太网帧头 14 字节ARP 报文 28 字节两部分拼在一起正好是 42 字节Winpcap 的 pcap_sendpacket 一次发出去。源码里定义了三个结构体ethernet_head、arp_head、arp_packetarp_packet 就是前两者的组合。各字段的偏移和取值如下表偏移字段长度值/说明0目的 MAC6ARP 请求为 FF:FF:FF:FF:FF:FF广播6源 MAC6本机 MAC12以太网帧类型20x0806 表示 ARP14硬件类型21 表示以太网16协议类型20x0800 表示 IP18硬件地址长度1619协议地址长度1420操作字段21 为 ARP 请求2 为 ARP 响应22发送端 MAC6源主机硬件地址28发送端 IP4源主机 IP32目的 MAC6请求时为 038目的 IP4要解析的目标 IP注意看偏移 20 的操作字段和偏移 22 的发送端 MAC接收线程判断是否收到 ARP 响应就是靠偏移 20 的值是否为 2提取源主机的 MAC 地址则从偏移 22 开始连续读 6 字节。原源码里直接用*(unsigned short *)(pkt_data20)这种裸指针强转来判定虽然能跑但换到 64 位系统或遇到非对齐访问时可能出问题这一点在避坑章会展开讲。2.2 字节序与结构体对齐htons 和 pack(1) 是动手前提第一次抄这份代码的人最容易在字节序上翻车。机器上跑的是小端序而网络传输规定是大端序所以在填充 ARP 帧时凡是多字节字段都要做一个转换。源码里反复出现的htons和htonl就是干这个的eh.type htons(ETH_ARP)把帧类型转成网络字节序ah.hardware_type htons(ARP_HARDWARE)转硬件类型ah.source_ip_add inet_addr(ip)则是把点分十进制的 IP 字符串直接转成网络字节序的 32 位值。注意inet_addr的返回值本身就是网络字节序所以它不需要再套一层htonl。另一个隐蔽的坑是 C/C 结构体默认对齐。ethernet_head 里有 6 字节数组、6 字节数组、2 字节 shortarp_head 里有 221126464 的混合类型。编译器默认会按 4 字节或 8 字节对齐填充空隙导致结构体实际占用的内存和报文在链路上的真实布局不一致。源码第一行就写了#pragma pack(1)强制结构体按 1 字节对齐这样struct arp_packet的sizeof才是干净的 42直接memcpy进发送缓冲区才不会多出无用字节。这一点没有商量的余地不写 pack(1)发出去的包全是废包。接收方向同理。解析响应帧时源码用pkt_data12、pkt_data20、pkt_data38这类偏移来读字段而不是把缓冲区强转成结构体指针就是绕开对齐问题的一种写法。如果你自己改代码我更推荐定义好结构体后用memcpy逐字段拷贝稳得多。2.3 网卡工作模式与混杂模式为什么必须开 PROMISCUOUS网卡有四种工作模式广播模式收目的地址为全 1 的广播帧多播模式收组播帧直接模式只收目的 MAC 是自己网卡的帧混杂模式则来者不拒所有流过网卡的帧都收。普通上网场景网卡跑在直接模式加广播模式上发给别人的单播帧根本不进你的接收队列。但 ARP 扫描的前提是「收到别人的 ARP 响应」这台响应主机把帧发给的是源主机不是你的网卡所以必须把网卡切到混杂模式才可能在链路上截获这些响应。源码里打开设备时传的第三个参数就是PCAP_OPENFLAG_PROMISCUOUS这一步是接收线程能抓到别人回包的关键。后面避坑章会讲一个常见现象有人把混杂模式去掉结果只能收到自己的 ARP 请求回包其他主机的响应全丢了。另外 pcap_open 的 snaplen 参数在源码里是 65536意思是每个包最多捕获 65536 字节足够覆盖以太网帧加 VLAN 头的场景一般照抄即可。超时时间 1000 毫秒是 pcap_next_ex 的阻塞上限调大了扫描会变慢调小了 CPU 占用会高。3. Winpcap 工程搭建VC 配置与第一个发包程序3.1 Winpcap 运行时与开发包驱动和 WpdPack 缺一不可Winpcap 不是单一文件它分两部分运行时驱动给操作系统装上抓包能力开发包 WpdPack 提供编译期需要的头文件和导入库。如果目标机器上没装过 Winpcap 驱动程序里 pcap_findalldevs_ex 会直接返回失败打印「找不到网卡」所以跑这个课设前必须先确认驱动已经安装。比较老的 Winpcap 4.x 版本在 Win10 以上系统有兼容性问题建议优先用能正常枚举到网卡的版本装完后可以用它自带的 wpcap.dll 是否存在于 System32 目录来快速验证。开发包解压后通常有 Include 和 Lib 两个目录Include 里有 pcap.h、pcap-int.h、Packet32.h 这些头文件Lib 下有 wpcap.lib、Packet.lib。源码 include 了 pcap.h 和 Packet32.h这两个正是收发数据帧的核心。编译时还要注意字符集问题老代码用的是 char 数组和 printf 输出如果工程默认是 Unicode 字符集某些 API 的宽窄字符转换会冒出警告甚至报错建议把字符集设成「未设置」或多字节字符集省去一堆麻烦。3.2 Visual C 工程配置Include、Lib 与附加依赖项Visual C 6.0 时代的配置方式和 Visual Studio 稍有不同但核心就三项头文件目录、库文件目录、附加依赖库。在 VC6 的 Tools - Options - Directories 里把 Include 和 Lib 路径加进去在项目设置 Project Settings - Link - Object/library modules 里追加 wpcap.lib 和 ws2_32.lib。后者是 Winsock 库地址转换和 socket 相关函数要用到它。库文件的附加依赖项还可以写在代码里用#pragma comment(lib, wpcap.lib)代替手工配置源码里没有写但补上这行会让工程更省事编译时少一步遗漏。工程还建议设置成「使用多字节字符集」。具体在 Visual Studio 的 Project Properties - Configuration Properties - General - Character Set 里选 Not Set。如果用较新版本的 Visual Studio 编译这份老代码C4996 这类安全函数警告大概率会出现可以在预处理器定义里加上_CRT_SECURE_NO_WARNINGS把 scanf、strcpy 这些老调用的警告压下去不影响功能。注意这个课设没有强调平台工具集但实用角度看Win7 和 Win10 上编译运行都没问题关键依赖还是 Winpcap 驱动本身。3.3 枚举网卡、选择适配器、打开设备三步走主程序的第一步是枚举网卡并让用户选择。源码用pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, alldevs, errbuf)拿到全部设备列表然后打印每张网卡的 name 和 description由用户输入序号。这里有个小坑PCAP_SRC_IF_STRING 在较新版本里已标记为 deprecated但老代码里仍然能用编译时会有提示不影响运行。设备列表用完要调用pcap_freealldevs(alldevs)释放源码里在正常流程和报错流程都做了处理。示例如下pcap_if_t *alldevs; // 设备链表头 pcap_if_t *d; int inum; char errbuf[PCAP_ERRBUF_SIZE]; if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, alldevs, errbuf) -1) { fprintf(stderr, Error in pcap_findalldevs: %s\n, errbuf); exit(1); } for (d alldevs, i 0; i inum - 1; d d-next, i);pcap_findalldevs_ex的第二个参数 NULL 表示不从远程机器抓包只枚举本机设备。循环语句for(d alldevs, i 0; i inum - 1; d d-next, i);的作用是跳转到用户选中的那张网卡这段代码把遍历和定位合并到了一行初看有点绕但效果等价于一个 while 循环。接着pcap_open打开设备参数列表里 65536 是抓包长度上限PCAP_OPENFLAG_PROMISCUOUS 开启混杂模式1000 是读取超时毫秒数。打开失败时程序会打印「适配器不被 WinPcap 支持」原因一般是驱动没装好或设备名带了特殊字符。打开成功后还要调用ifget和GetSelfMac拿到本机 IP、掩码和 MAC这些信息后面扫描要用。4. 双线程扫描实现发广播包、收响应、解出 IP-MAC4.1 包结构定义与构造三个结构体拼出 42 字节源码把帧结构定义成三个结构体ethernet_head 表示以太网帧头arp_head 表示 ARP 报文arp_packet 把两者组合成最终完整的包。定义方式如下#pragma pack(1) struct ethernet_head { unsigned char dest_mac_add[6]; // 目的 MAC unsigned char source_mac_add[6]; // 源 MAC unsigned short type; // 帧类型0x0806 为 ARP }; struct arp_head { unsigned short hardware_type; // 硬件类型1 为以太网 unsigned short protocol_type; // 协议类型0x0800 为 IP unsigned char hardware_add_len; // 硬件地址长度6 unsigned char protocol_add_len; // 协议地址长度4 unsigned short operation_field; // 操作字段1 请求2 响应 unsigned char source_mac_add[6]; // 发送端 MAC unsigned long source_ip_add; // 发送端 IP unsigned char dest_mac_add[6]; // 目的 MAC unsigned long dest_ip_add; // 目的 IP }; struct arp_packet { struct ethernet_head ed; struct arp_head ah; };#pragma pack(1)是这一切的前提它在结构体定义之前取消编译器的自动填充。unsigned long在 32 位和 64 位 Windows 上长度不同但 IP 地址固定是 4 字节这份老代码在 64 位系统下编译时sizeof(arp_head)可能会变成 32 而不是 28因为 unsigned long 在 LLP64 数据模型下是 4 字节不变这里相对安全。构造包时先 memset 缓冲区为 0再把 eh 和 ah 依次 memcpy 进 sendbuf操作字段置为 ARP_REQUEST目的 MAC 置为全 1 广播地址源 MAC 和源 IP 填本机真实值目的 IP 填要扫描的地址。这些代码在 GetSelfMac 和 SendArpPacket 里各出现一次逻辑基本一致。4.2 构造 ARP 请求广播地址与真实源地址的填充顺序构造请求包最关键的细节是ARP 请求里的目的 MAC 是 0源 MAC 是本机 MAC源 IP 是本机 IP目的 IP 是目标地址。源码里在 GetSelfMac 函数中故意把源 IP 设成100.100.100.100这是一个「假 IP」用来骗本机网卡回包从而从响应帧里提取自己的真实 MAC。这个技巧值得解释一下因为要拿到自己的 MAC但标准库没有直接接口就发一个目的 IP 为假地址的 ARP 请求本机协议栈会认为这个 IP 不存在而丢弃但网卡驱动层仍会回一个 ARP 应答说「100.100.100.100 不存在」应答帧里带着本机 MAC 地址在混杂模式下就能收到。真正扫描时SendArpPacket 线程填充的是主程序传进来的真实 IP 和真实 MAC。每次循环把目的 IP 写进 ah.dest_ip_add然后pcap_sendpacket发送。发送前要保证 eh.source_mac_add 和 ah.source_mac_add 一致都填本机 MAC否则某些严格实现的交换机或主机检测到帧内 MAC 不一致会丢弃。发送函数返回值是 0 表示成功非 0 表示失败失败时可以用 GetLastError 查看原因实践中最常见的失败就是网卡未启用或驱动异常。4.3 发送线程从网络地址扫到广播地址Sleep 控制频率发送线程负责把 ARP 请求广播给整个 /24 网段。核心逻辑是先用本机 IP 和子网掩码按位与算出网络地址然后从网络地址的下一个 IP 开始逐个向后扫 255 个地址。代码里有一处隐蔽的字节序操作需要仔细看unsigned long myip inet_addr(ip); // 二进制网络字节序 unsigned long mynetmask inet_addr(netmask); unsigned long hisip htonl((myip mynetmask)); // 转成主机序再1 for (int i 0; i HOSTNUM; i) { ah.dest_ip_add htonl(hisip i); // 再转回网络序发送 memset(sendbuf, 0, sizeof(sendbuf)); memcpy(sendbuf, eh, sizeof(eh)); memcpy(sendbuf sizeof(eh), ah, sizeof(ah)); pcap_sendpacket(adhandle, sendbuf, 42); Sleep(50); }inet_addr返回的是网络字节序myip mynetmask得到网络地址但此时的网络地址也是网络字节序。如果直接在这个值上做算术加 1得到的结果是错的因为字节序反了。所以源码先用htonl转成主机序拿到可以正常加减的整数得到目标 IP 后再用htonl转回网络字节序赋给 dest_ip_add。这一步很容易被忽略但它决定扫描是从 10.0.0.1 开始还是从 10.0.0.16777216 这种错误地址开始。Sleep(50)是限速手段。不 Sleep 的话255 个包会在几十毫秒内全部抛出轻则 CPU 飙高重则被交换机或目标主机的防 ARP 风暴机制限流大量请求根本到不了目的地。50 毫秒意味着整个扫描大约持续 13 秒这个节奏在宿舍网、实验室交换机上都不会触发限速。如果你在更严格的网络环境把 Sleep 提到 100 是更稳妥的选择代价是扫描时间拉长到 25 秒。4.4 接收线程pcap_next_ex 轮询与响应帧解析接收线程和发送线程并行跑。接收线程的任务是在循环里调用pcap_next_ex从网卡读取数据包判断是不是 ARP 响应是的话提取发送端 MAC 和 IP 打印出来。响应判定的代码写法值得逐行看if (*(unsigned short *)(pkt_data 12) htons(ETH_ARP)) { // 帧类型是 ARP if (*(unsigned short *)(pkt_data 20) htons(ARP_REPLY)) { // 操作字段是 2 printf(IP地址:%d.%d.%d.%d MAC地址:, recv-ah.source_ip_add 255, recv-ah.source_ip_add 8 255, recv-ah.source_ip_add 16 255, recv-ah.source_ip_add 24 255); for (int i 0; i 6; i) { Mac[i] *(unsigned char *)(pkt_data 22 i); printf(%02x, Mac[i]); } printf(\n); } }偏移 12 是帧类型字段0x0806 说明载体是 ARP偏移 20 是操作字段2 说明这是 ARP 响应而不是请求。满足这两个条件后发送端 MAC 在偏移 22 处连续 6 字节发送端 IP 在偏移 28 处占 4 字节。源码里用recv-ah.source_ip_add的方式读 IP这是把 pkt_data 强转成了 arp_packet 指针依赖了#pragma pack(1)下结构体内存布局和帧一致这一点。我自己改代码时会用 memcpy 把 IP 的 4 个字节拷出来再拼虽然多几行但逻辑更直白也不会受编译器设置影响。4.5 主流程收尾双线程与 flag 结束信号主函数在准备好参数后创建两个线程一个跑 SendArpPacket一个跑 GetLivePC然后主线程停在 getchar 上等待用户按键。这里有个不太显眼的细节全局变量 flag 初始为 FALSE发送线程在扫描完 255 个 IP 后再 Sleep(1000) 等待响应落袋然后把 flag 置为 TRUE。接收线程每轮循环检查 flag读到 TRUE 就打印「扫描完毕」并退出循环。这是一个朴素的生产者-消费者同步用全局变量实现不涉及锁在课设场景下够用。但要注意一个边界条件发送线程最后一次发包后 Sleep(1000) 才置 flag而接收线程在 flag 为 FALSE 时会持续pcap_next_ex收包所以理论上 1 秒的缓冲足够让慢速主机的响应到达。如果目标网络有主机响应延迟超过 1 秒那台主机就会被漏掉这种场景在无线网络或跨交换机环境下偶尔会发生。想要更稳可以把那个 Sleep(1000) 加到 2000或者扫描完后再额外轮询两轮。线程退出机制也很粗糙没有 WaitForSingleObject主线程 getchar 后直接 return 0进程结束后线程自然终止这在课设验收场景下没有大问题但拿到真实工具里用就要补线程回收。5. 避坑与常见问题六个最容易翻车的现场5.1 结构体没按 1 字节对齐发出去的包没人理现象程序提示发送成功但局域网里所有主机都不回 ARP 响应接收线程什么都收不到。有人把原因归结为网卡问题折腾驱动半天发现没用。原因#pragma pack(1)被注释掉或挪到了结构体定义之后编译器按默认规则在结构体内填充了对齐字节。此时sizeof(arp_packet)大于 42memcpy把多余的空洞字节也作为帧内容发到了链路上破坏了 ARP 报文格式接收方解析失败直接丢弃。解决把#pragma pack(1)放在所有结构体定义之前并且确认在使用sizeof(arp_packet)或sizeof(eh) sizeof(ah)拼包时计算结果严格等于 42。可以在 main 里加一句printf(%d\n, sizeof(struct arp_packet));输出不是 42 就说明对齐没生效。5.2 字节序没换算扫描范围跑到奇怪网段现象程序正常发包也能收到响应但打印出来的 IP 段明显不对比如本机是 192.168.1.100扫描结果却落在 192.168.1.0 之外的其他网段甚至出现 168.192.1.100 这种字节顺序颠倒的 IP。原因inet_addr返回网络字节序直接拿它做按位与和算术加法结果是小端视角下混乱的数字。扫描起点算错后面 255 个目标全错自然收不到正常响应。解决严格照抄源码的两步转换先htonl(myip mynetmask)转成主机序算起点再htonl(hisip i)转回网络序填入帧。想验证的话可以在循环里用printf(%s, inet_ntoa(...))打印一下当前目的 IP 字符串确认从 .1 开始递增到 .255。5.3 混杂模式没生效只能收到自己的回包现象发送线程自己的 ARP 请求能收到回包但其他主机的 ARP 响应一个都抓不到扫描结果只有本机一条记录MAC 还是自己网卡的。原因网卡没切到混杂模式。pcap_open 的第三个参数没有传PCAP_OPENFLAG_PROMISCUOUS或者某些虚拟网卡驱动对混杂模式支持不完整。直接模式下网卡只接收目的 MAC 是自己的帧别人回给源主机的 ARP 响应根本进不了接收队列。解决确认打开设备时代码完整传入了混杂模式标志位。如果是 VMware 虚拟机还要确认虚拟交换机设置允许混杂模式或者直接把网卡模式切到桥接NAT 模式下宿主机的 ARP 包不一定能透传到虚拟机。5.4 扫描速度太快被交换机限速大量主机漏报现象在部分网络环境下扫 255 个地址回包寥寥无几但单独 ping 某台主机又能通。把 Sleep(50) 去掉后问题更严重几乎全部漏报。原因AR P 请求是以太网广播帧交换机收到大量广播帧时会触发风暴控制或速率限制策略超过阈值的帧直接丢弃。目标主机本身也有 ARP 速率限制短时间内收到几十上百个请求会丢包。解决把Sleep(50)改成Sleep(100)或 200让整个扫描在 25 到 50 秒内完成绝大多数家用路由器和交换机不会限制这个频率。更稳的做法是分片扫描比如一次只扫 64 个地址停 2 秒再扫下一片。5.5 64 位系统下裸指针解引用读取字段崩溃现象在 64 位 Windows 上编译运行程序不定时崩溃崩溃位置落在接收线程解析包的部分。把工程改成 32 位编译后问题消失。原因源码里大量使用*(unsigned short *)(pkt_data 20)这类非对齐指针强转。x86 架构允许非对齐访问但 x64 下某些情况下会触发保护异常加上 unsigned long 在 64 位下仍是 4 字节但编译器生成的访存指令可能按 8 字节对齐优化导致越界读。这种问题表现不稳定属于典型的「玄学崩溃」。解决把所有裸指针强转改成memcpy到局部变量后再解析例如unsigned short op; memcpy(op, pkt_data 20, 2);判断 op 2。这样段对齐、字节序都自己控制代码也能同时在 32 位和 64 位下跑。顺带把打印 IP 的方式改成按字节printf(%d.%d.%d.%d, buf[28], buf[29], buf[30], buf[31])彻底摆脱结构体强转。5.6 杀毒软件或系统防火墙拦截 Winpcap 的抓包操作现象程序编译通过运行后马上被 Windows Defender 或第三方杀毒软件拦截提示「程序试图访问网络数据包」并终止进程。有些机器上 pcap_sendpacket 甚至直接返回错误码。原因Winpcap 的底层是内核驱动 npf.sys它把自己挂到网卡协议栈上时行为比较敏感杀毒软件默认把这种操作标记为抓包嗅探行为。老版本驱动在 Win10 以上的兼容性也一般签名过期会导致加载失败。解决优先确认 Winpcap 运行时版本能正常加载不行就换用 Npcap 作为替代运行时并适配头文件差异。跑课设时临时把杀毒软件的网络防护或实时监控关掉但这种场景一般限制在学生本机实验室估计不需要关。不需要用其他抓包工具直接信源码那套就行。6. 结果落地技巧从打印 IP-MAC 到可复用的扫描输出6.1 先用单 IP 定向发包验证链路再上全量循环拿到代码第一件事不要直接扫 255 个地址我一般会把循环上限临时改成 1只扫本机的网关或另一台已知设备确认发送、接收、解析三个环节都通。这一步能排除掉至少一半的坑。验证时目的 IP 固定填网关地址发送完请求后 Sleep(200)再打印接收线程解析出的 MAC看是不是网关的物理地址。通了这个台阶再放开循环用 Sleep(50) 全量扫描得到的列表就会干净很多。因为如果链路本身是断的全量扫出来的只有一片空白你根本分不清是代码问题还是环境问题。6.2 把输出写进日志文件方便课设报告截图和比对打印到控制台的结果关掉窗口就没了课设报告要贴数据、要前后对比把输出重定向到文件更实用。接收线程里打印 IP-MAC 的地方加一个文件写入分支每次解析到合法响应就追加一行格式用 CSV方便后来导入 ExcelFILE *fp fopen(arp_result.csv, a); if (fp ! NULL) { fprintf(fp, %d.%d.%d.%d,%02x:%02x:%02x:%02x:%02x:%02x\n, ip1, ip2, ip3, ip4, Mac[0], Mac[1], Mac[2], Mac[3], Mac[4], Mac[5]); fclose(fp); }文件打开方式用追加模式a是因为接收线程在循环里会触发很多次重复打开关闭虽然有小开销但课设规模完全扛得住。CSV 的好处是可以用 Excel 直接打开按 IP 排序一眼看出哪些主机活跃。如果你不想每次运行都累积旧数据改成w模式即可每次从空文件开始。这个细节不是源码里自带的是我做类似扫描工具时的常规加强课设报告的「运行结果」部分贴这种格式化输出比贴控制台截图要规范得多。6.3 扫描完成后多等一轮别急着退出源码用flagTRUE当扫描结束信号接收线程看到 flag 就退出。但这会造成一个实际问题发送线程在 Sleep(1000) 后置位 flag此时慢速主机刚到 ARP 请求响应还没发回来接收线程已经退出了漏掉那台主机。解决思路很简单把Sleep(1000)改成两次收包循环或者置 flag 后不立即退出而是多轮询 2 秒。我在改这份代码时会用下沉方式处理置 flag 后接收线程把while(true)改成while(counter 20)每轮 Sleep(100)计数到 20 再退出相当于多给了 2 秒的尾部窗口。如果你需要保证不漏报这是最关键的一处改动。6.4 扫描结果的验证技巧ping 一下再做交叉比对ARP 扫描得到的主机列表可以用 ping 命令快速验证。先把扫描到的 IP 记在一边再对同一个网段批量 ping 一遍对比 ARP 响应列表和 ICMP 响应列表的重合度。两者重合的主机基本就是活跃主机了只在其中一侧出现的主机要么是防火墙挡了 ICMP要么是 ARP 缓存没更新需要重扫一次。从那以后我每次做抓包程序都强制走一遍「单 IP 验证 → 全量扫描 → ping 交叉比对」的流程确认输出不是靠运气跑出来的才敢贴到报告里。希望这份拆解能帮你的课设少走几步弯路动手时把帧结构和字节序看紧一点大概率一次就跑通。本文还有配套的精品资源点击获取
返回列表