拓冰建站拓冰建站
首页 / 资讯中心 / 正文

数据链路层帧格式详解:以太网、VLAN与802.11帧结构及抓包实战

做过几年网络协议栈和抓包调优的人十有八九都有过这种经历明明写的应用层代码逻辑完全没问题数据发出去就石沉大海或者抓下来的报文用Wireshark一打开看到一堆乱码一样的二进制数据就开始头皮发麻。这种时刻问题往往不在应用层而藏在数据链路层——这一层不负责你传的是什么内容但它决定了你的数据能不能在局域网里找到正确的下一跳以及接收方能不能识别出你发的这坨字节流到底从哪开始、在哪结束。今天这篇就把数据链路层的帧格式好好扒一扒。我会从以太网最基础的帧结构讲起再把VLAN帧、802.11无线帧的差异也顺带理清最后结合Wireshark实际抓包、海明码校验原理这些实操内容逐个拆解平时最容易踩坑的字节序、长度字段、校验范围之类的问题。不管是刚开始学网络协议栈的初学者还是需要日常分析报文、抓包排查的运维和开发这篇文章都应该有你能直接用上的内容。1. 数据链路层的基本功能与设计逻辑1.1 数据链路层到底在解决什么问题数据链路层位于网络层之下、物理层之上很多人把它理解成把网络层的IP包装进一个信封里交给物理层的过程这个类比大方向对但细节上不够完整。它实际上要解决的问题有这么几个一是封装成帧也就是给IP包加上头部和尾部让接收方能从比特流里识别出帧的边界二是透明传输必须解决数据中出现帧定界符被误判的问题三是差错检测发送的数据在物理传输中可能被干扰帧格式里必须带上校验信息让接收方判断数据有没有损坏四是介质访问控制多个设备共享同一个物理链路时怎么决定谁先发送、怎么避免冲突。如果只用一句话概括数据链路层的作用我觉得就是把一个可能出错的物理链路包装成一个让上层网络层感觉像基本可靠的逻辑链路。网络层不需要操心物理层那里信号衰减、电磁干扰这些破事它只要把IP包往下交给数据链路层让链路层保证尽力送到相邻节点就行。1.2 从比特流到帧封装与解封装的过程发送端的数据链路层收到网络层下发的IP数据报之后会做这么几件事在数据前面加上帧头在数据后面加上帧尾有的协议只有帧头没有帧尾比如以太网然后整体交给物理层转换为比特流发送出去。接收端则是反过来的过程物理层收到比特流后数据链路层先根据帧定界信息识别出一帧的起始和结束然后检查校验字段判断这帧有没有损坏最后去掉帧头和帧尾把IP数据报向上交给网络层。这里有一个特别容易让初学者绕晕的点数据链路层的帧和处理IP分片时的片不是一回事。IP包在数据链路层里就是一个完整的载荷帧格式决定的最大传输单元MTU如果小于IP包的长度网络层会先分片再下发给数据链路层数据链路层不负责分片重组。MTU常见的值是1500字节这就是以太网帧里数据字段最多能装下的IP包长度一旦超过这个值IP层就得动手切了。1.3 为什么今天还需要关注帧格式可能有朋友觉得现在大家都是TCP/IP协议栈一通操作底层的帧格式早就被封装进网卡驱动和内核协议栈里了做应用开发的根本不用管这些。这个想法某种程度上没错但只要你的工作涉及这几个方向帧格式知识就需要随时能拿出来用排查局域网传输性能问题时的抓包分析、交换机端口镜像和VLAN配置、嵌入式设备里直接操作网卡寄存器的驱动开发、以及各种需要构造原始数据包的测试工具开发。举个例子我曾经排查过一个奇怪的问题同一台交换机下两台服务器通过千兆网卡传输大文件带宽始终跑不满只有理论值的六成左右。一开始怀疑是TCP窗口大小、网卡队列中断之类的常规问题折腾半天没效果。后来抓包仔细看发现帧结构里VLAN标签一直在变说明交换机配置了多个VLAN且设备间通信经过了VLAN间路由流量平白多走了一道三层转发。如果不懂VLAN帧格式的构成抓包时很可能会直接忽略掉帧头里那四个额外字节的信息问题排查方向就完全偏了。2. 以太网帧格式核心解析2.1 经典DIX帧格式和802.3帧格式的差别说到以太网帧格式市面上一般会提到两种一种是DEC、Intel、Xerox三家公司在1980年联合制定的DIX以太网规范后来被IEEE 802.3吸收为正式标准另一种是最早的802.3规范。两者的关键区别其实就在帧头里的一个字段。DIX的帧结构是这样的前导码8字节实际上前7字节是同步比特最后1字节是帧起始定界符SFD紧接着是6字节目的MAC地址6字节源MAC地址然后一个2字节的类型字段用来告诉上层网络层这帧里装的是什么协议比如0x0800表示IPv4、0x0806表示ARP、0x86DD表示IPv6。类型字段后面就是IP数据报本身最后是一个4字节的帧校验序列FCS。而最开始的IEEE 802.3规范没有沿用类型字段它把同样的2字节位置改成了长度字段表示的是后面数据部分实际有多少字节。这样一来接收方怎么区分一个帧是DIX格式还是802.3格式就是看这个2字节字段的数值。如果值大于1500那它肯定是类型字段因为长度不可能超过MTU 1500如果值小于或等于1500那它就是长度字段。这个设计非常巧妙后来的802.3x标准又把这个长度字段位置和DIX的类型字段统一兼容了用同样的位置表示长度或类型具体是哪个含义由数值大小来区分。前导码这个点也需要稍微记一下。前导码和SFD并不是算在帧长度里的抓包软件上显示的以太网帧长度一般是从目的MAC地址开始算的也就是14字节头部加数据部分加4字节FCS。前导码属于物理层的同步机制接收方的网卡靠它做时钟同步和比特对齐识别到SFD的最后一字节的末位变成1之后才开始正式解析后面地址和数据字段。2.2 各字段逐字节拆解从抓包和构造报文的角度我把以太网帧的字段从头到尾列在下面每个字段的含义和注意事项也一起说明。目的MAC地址6字节这一帧要发给谁。可以是单播地址、广播地址ff:ff:ff:ff:ff:ff或多播地址。交换机就是靠这个地址做转发决策的。源MAC地址6字节这一帧是谁发的。正常情况下源MAC地址必定是单播地址如果抓到源MAC是多播或广播地址那基本可以断定这帧是伪造的或者网卡异常了。类型/长度字段2字节如上面说的大于等于0x0600即1536十进制时解释为上层协议类型否则解释为数据长度。具体常用值0x0800 IPv40x0806 ARP0x8100 VLAN标签0x86DD IPv60x8847/0x8848 MPLS单播/多播。数据部分46-1500字节承载上层协议数据。规范和常识要一起看以太网标准规定帧的最小长度是64字节这个长度是从目的MAC地址开始算到FCS结尾。帧头14字节加FCS 4字节数据部分最短就得是46字节。如果上层数据不足46字节数据链路层会在IP包后面填充Padding补齐到46字节。如果帧总长小于64字节就属于 runt frame过短帧一般是有问题网卡收到这种通常直接丢弃或上报异常。FCS校验序列4字节用CRC32算法对整个帧从目的MAC到数据部分末尾计算出来的校验码。发送方计算填入接收方用同样算法对收到的帧做CRC计算结果如果不匹配说明帧在传输过程中出了差错直接丢弃。这里要特别提醒一个容易出错的点抓包工具看到的帧长度和帧在线上实际占用的长度是两码事。Wireshark上看到的长度往往包含了前导码或者在以太网高层的交付格式里有些不一致。另外很多网卡支持硬件卸载计算和校验FCS抓包时某些帧的FCS可能是网卡自动填的并不一定准确分析时要留意。2.3 最小帧长度和冲突检测的逻辑关联以太网为什么把最小帧长度定在64字节这是由CSMA/CD碰撞检测机制决定的。老式共享式以太网在发送数据的同时也在监听信道如果两个设备同时发送就会发生冲突。设计的关键在于发送方必须在自己的发送过程中就能检测到冲突冲突信号传回来再被发送方识别到这段时间内发送方不能都已经发完了。考虑信号在总线两端的往返时间在最坏的网络直径情况下以太网的设计参数确保发送一帧所需的时间至少是冲突检测窗口的两倍。64字节在10Mbps速率下传输耗时是51.2微秒正好和往返传播延迟的上限匹配。今天虽然交换式以太网已经是全双工通信了很少因为碰撞导致问题但这个最小帧长度约束还是被保留了下来兼容性上必须考虑。3. VLAN帧格式与802.1Q标签3.1 标准以太网帧里的不速之客802.1Q标签随着网络规模扩大二层广播域太大时广播风暴、安全隔离、网络管理都会出现麻烦。VLAN技术就是把一个物理局域网从逻辑上切分成多个独立的广播域。但交换机怎么判断一个帧属于哪个VLAN单靠标准以太网帧本身没有这个信息。于是IEEE 802.1Q标准定义了VLAN标签在源MAC地址和类型/长度字段之间插入了4个字节。加了802.1Q标签后的帧结构变成目的MAC 6字节、源MAC 6字节、VLAN标签4字节、类型/长度2字节之后才是数据部分和FCS。注意插入了4字节之后原来的FCS计算范围也变了FCS必须针对加了标签的完整帧重新计算这也是为什么很多抓包工具默认显示的是去掉FCS的头部信息分析VLAN帧时如果自己手工算校验很容易被这个坑到。3.2 四个字节拆开看TPID、PCP、DEI、VIDVLAN标签这4字节可以分成几个部分来理解。TPID2字节标签协议标识固定为0x8100表示这个帧是一个带VLAN标签的帧。接收方在没有先看这个字段之前还会以为它是类型/长度字段0x8100正好大于1500所以语义上也不会和正常类型/长度混淆。PCP3比特优先级码点表示802.1p优先级取值范围0到7数值越大优先级越高。这个字段在QoS流量分类、语音视频流优先转发上发挥作用。DEI1比特丢弃合格指示原CFI。在以太网环境中表示如果遇到拥堵是否可以优先丢弃通常为0。VID12比特VLAN标识符取值范围0到4095。其中0表示不属于任何VLAN通常用于优先级处理但不参与VLAN转发4095是保留值实际可用的VLAN ID基本是1到4094。默认VLAN通常是1。TPID的0x8100是IEEE 802.1Q的标准值但实际网络里还会看到其他值比如0x88A8表示运营商级QinQ的外层标签0x9100、0x9200也是某些厂商自己实现的VLAN标签类型。抓包看到TPID不是0x8100时别急着认为协议解析出错先确认是不是涉及运营商专线或者某些厂商私有协议。3.3 为什么加标签会引发MTU和最大帧长的连锁反应标准以太网帧的数据字段最大是1500字节这是一般意义上MTU的来历。但是如果交换机/链路上启用了VLAN标签每个帧会额外多出4个字节而链路的最大帧长通常还是按1518字节14字节头1500字节数据4字节FCS来限制——严格说没有VLAN标签限制是1518有标签时允许到1522字节。这里就会产生一个常见的MTU不一致问题。实践中最常见的坑是交换机的某个接口启用了802.1Q封装但两端设备的MTU没有相应调整或者反过来两端的MTU设置成1500但中间链路启用了大帧加上标签导致某些长度逼近边界的报文被中间设备丢弃。比如很多虚拟化平台默认把虚拟机网卡的MTU设为1500但承载业务的VXLAN或其他叠加网络需要加额外的头部开销如果底层交换机没有启用巨型帧一般是9000就会频繁出现大包不通、小包正常的现象。确定这类问题的方式很简单ping不通但小包能通时用带DF标志的大包ping探测MTU路径基本就能定位。另外在配置交换机的时候还有一点要留意Access口和Trunk口对VLAN标签的处理方式不同。Access口一般只属于一个VLAN发送帧时不带标签会把标签去掉再发Trunk口允许传输多个VLAN的帧默认会带上802.1Q标签但有一个native VLAN通常VLAN 1的帧是走不打标签的。如果两台设备之间配置成了Trunk一端把某个VLAN设为native另一端没有帧在链路上有没有标签就会和期望不一致结果就会表现为某些VLAN通信异常但抓包看到报文里没有VLAN标签排查的时候一定要对照这个细节。3.4 多级标签QinQ帧格式当运营商需要在一个物理链路上承载多个客户的VLAN域或者企业网络需要更大的VLAN扩展空间时可以在一个帧里打上两个802.1Q标签这就是QinQ或者802.1ad以前也叫802.1Q-in-Q。标准QinQ外层TPID是0x88A8内层继续用0x8100。抓包分析时如果看到一个帧里有两个VLAN标签内层的VID才是客户私网的VLAN外层的VID一般是运营商分配的。这种帧出现时FCS是对整个双层标签后的数据做校验的分析时如果手动修改了内层VID再重算校验一定别漏了外层标签的存在。另外某些交换机在端口模式下会有一个QinQ角色配置配置不当会出现帧标签层数和预期不一致的问题这类故障的排查核心就是抓包确认帧里的标签结构。4. 数据链路层差错检测海明码和CRC4.1 帧校验为什么不能只靠一种方法数据链路层面对的是不可靠的物理层电磁干扰、信号衰减、硬件故障都可能让比特发生翻转。为了检测和纠正差错常用办法大致分两类一类是能够检错并大概率知道错在哪可以纠正的纠错码另一类是只能检错不能纠正的检错码。海明码属于前者CRC循环冗余校验属于后者中的代表。以太网帧尾的FCS使用的就是CRC32它算得飞快、检错能力极强但不会尝试去还原出错的数据因为以太网的策略就是检错、丢弃、交给上层重传这种丢弃后重传的代价在高速网络上是可以接受的。而海明码的设计目标不太一样它加入了足够的冗余信息使得接收方不仅知道有错还能定位出错比特的位置从而直接纠正单比特错误更适用于那些无法方便重传的场景比如某些无线通信和存储系统。4.2 海明码核心原理与计算示例海明码通过插入冗余校验位来对数据位进行分组校验。给定数据位数m需要的校验位数r必须满足2^r m r 1。这里的含义是r个校验位能表示2^r种情况其中1种表示无错剩下2^r-1个情况需要对应mr个比特位置每个位置都可能是出错的位置。举个例子数据位m4需要满足2^r 4r1r3时2^38 71不对mr18刚好相等所以r3够用。因此4比特数据需要3个校验位最终编码长度是7比特。海明码的具体排位方法校验位放在2的幂次位置上也就是第1位、第2位、第4位……数据位按顺序填在剩余位置。每个校验位负责校验一批特定的位置规则是第i个校验位位置为2^(i-1)负责校验所有二进制表示中该位为1的位置。接收端收到后对所有校验位做校验计算如果所有校验结果都是0就认为没有错误如果非零把这些校验位结果从低到高组合成一个二进制数这个数就是出错比特的位置编号。我个人建议真去手算一次不要只盯着公式。比如发4位数据1011海明码生成后是1010101如果你其中的第5位被干扰翻转为1接收方重新计算所有校验位结果组合成101即5定位到第5位是错的把它还原就行。在考试、面试或者设计某些底层协议时这类逻辑经常会被拿出来考原理理解了就不需要死记硬背。4.3 CRC32在以太网帧里的具体应用CRC在数据链路层里用得比海明码广泛得多。以太网FCS使用的CRC32采用多项式0x04C11DB7IEEE 802.3定义的版本在算法上还加了一些初始值和结果异或的处理。不过如果你只是做协议开发一般不关心底层那个多项式的具体手工计算过程更多是靠硬件或者现成库函数完成。但在排查网络问题的时候是要理解CRC错误意味着什么的。交换机上如果看到类似CRC errors或FCS errors的计数器快速增长通常对应这几类情况物理层链路质量差、网卡或交换机端口光模块信号异常、网线质量不佳或者过长、设备硬件故障。举例来说我曾经遇到一个办公室网络频繁掉线的情况网管在交换机上查端口统计数据发现CRC错误计数在几分钟内增加了上万但链路协议状态、协商速率都显示正常。后来重新压制了网线两端的水晶头CRC错误计数停止增长问题就解决了。这说明CRC错误很多时候是物理层的问题数据链路层只是负责把这个坏帧检测出来并丢弃真正的原因要靠物理层排障来解决。5. 从抓包视角看各种帧格式的实际样貌5.1 Wireshark中几个关键列的读法分析和验证帧格式最直接的手段就是抓包。Wireshark打开一个包后在Frame部分会看到接口ID、抓包时间、帧长度、被抓包接口的元数据紧接着是Ethernet II部分显示目的地址、源地址、类型如果是VLAN帧会多出802.1Q Virtual LAN部分。通常在看帧格式时Wireshark的Packet Details面板已经做了字段级解析但要想真正理解帧的二进制结构建议打开View - Reload as File Format或者直接在十六进制视图里对照着看。举个例子一个IPv4帧的十六进制开头通常是这样ff ff ff ff ff ff目的广播然后源MAC然后是08 00IPv4类型。如果你看到一个帧的前面有0x8100那就说明它带VLAN标签后面那两个字节里的低12位就是VID。关键点Wireshark显示的Length字段可能会因捕获方式不同有差异。在Linux上用AF_PACKET套接字抓包和用普通的libpcap抓包某些环境下捕获到的帧可能已经去掉了FCS有些网卡驱动会保留FCS。分析时别因为帧尾没有FCS就以为协议栈出错了。5.2 普通IP帧、ARP帧、VLAN帧和QinQ帧的抓包对比我这里列一个常见帧的抓包特征速查表分析时很有用帧类型以太网类型/TPID头部总长典型负载内容抓包特征IPv4单播帧0x080014字节TCP/UDP/ICMP报文类型字段后直接是IP头首字节0x45ARP请求/应答0x080614字节ARP报文28字节类型0x0806负载前两字节0x0001IPv6单播帧0x86DD14字节IPv6报文类型0x86DDIP头版本字段0x6802.1Q VLAN帧0x810018字节原以太网帧内容TPID 0x8100紧跟VID和PCPQinQ帧0x88A8 0x810022字节内层VLAN原帧外层TPID 0x88A8内层0x8100MPLS帧0x8847/0x884814字节MPLS标签栈MPLS报文类型0x8847负载以MPLS标签头开头用Wireshark里的Packet Bytes视图可以很直观地看到每种帧在十六进制层面如何组织。很多朋友看抓包软件只盯着高亮解析的字段但有时候协议解析器可能因为某些字段不标准而解析错位这时候切到十六进制视图对照基础知识来判断反而是最快的定位方式。5.3 抓包时如何验证FCS是否有效如果网卡支持并开启了硬件校验和收到的帧里的FCS会被硬件验证Wireshark会在Frame部分显示Frame check sequence: 0x... [correct]。如果是软件抓包有些抓包点拿不到FCS或者拿到的FCS已经被剥离此时Wireshark可能不显示或显示为ignored。验证帧是否有FCS错误最直接的办法是到交换机或网卡驱动层去看硬件计数器。Linux下可以用ethtool -S eth0查看rx_crc_errors这类计数器或者用ifconfig看RX errors。我排障时一般先把Wireshark的显示过滤器和网卡统计结合起来Wireshark只能看到协议栈递上来的帧而物理层的坏帧早在网卡驱动阶段就丢了抓包工具根本看不见。所以如果觉得明明抓不到坏帧但网络还是不稳定一定要去看驱动层的计数器这个经验在排查物理链路问题的时候特别重要。6. 帧格式相关的常见问题与排查思路6.1 类型/长度字段的识别混淆很多人初学时会卡在到底怎么看这个2字节是类型还是长度的问题上。简单总结一下在标准以太网II帧即DIX帧里它就是类型在最早期802.3帧里它被定义为长度。现在的网络设备基本都用DIX格式所以实际通信里它多半是类型字段。但要注意某些协议分析工具在遇到长度值小于1500的帧时会把它当802.3长度字段解析这会导致后面的数据解析错位。排查时如果看到Wireshark解析出的Ethernet部分出现奇怪的padding或者协议识别错误可以怀疑是不是帧格式本身的语义和软件预设不一致。优先以十六进制数据为准不要被上层解析器带偏。6.2 最小帧长度和填充字段带来的干扰当上层数据很短时比如一个纯粹的ACK包IP包加上TCP头也没多少字节为了凑够46字节的最小数据长度链路层会在数据部分后面填充Padding。Wireshark看到这种帧时会在IP/TCP报文的末尾显示padding。有些场景下这些填充字节会被误当成有效载荷来分析。比如你基于原始套接字抓包然后自己写程序解析帧如果没考虑填充字段就会把Padding当成应用数据导致解析结果里多出一串0。处理思路是先按帧头部里的长度字段获得真实载荷长度再忽略该长度之后的所有尾部数据不要在以太网层去强行数数据长度因为填充是46字节。6.3 MTU和交换机默认巨型帧设置的坑交换机、路由器、云主机的MTU默认基本都是1500但实际网络中总会出现某些例外。比如数据中心内部常用的jumbo frame巨型帧往往把MTU调到9000用于存储网络或大数据传输提高吞吐。问题是如果一条链路上某个设备启用了巨型帧、另一个设备没有或者中间链路因VLAN标签、隧道封装等原因而增加了额外开销大包就会被丢弃或分片。排查时建议做一个分段MTU发现用ping命令带DF标志发送不同大小数据包逐步确认哪一段路径的MTU被卡住。Linux下可以用ip link show查看接口MTUWindows下可以用netsh interface ipv4 show subinterfaces。如果发现某些端口启用了VLAN交换机端口MTU需要留出额外空间通常也建议把MTU设为1504或1522以适应标签开销。6.4 CRC错误记为0但实际收包异常的少见问题有一种情况比较非常见交换机端口的CRC错误计数为0但链路就是不正常。你把抓包软件挂在端口镜像上也只能看到重传一大片。这种时候多半不是帧校验的问题而是更高层的其他问题比如TCP分片重组超时、网卡驱动缓冲队列耗尽、CPU软中断处理不过来导致丢包。因此我要强调一句帧格式和FCS只是链路层质量的一个维度排查速度一定要有大局观先把物理层、队列、CPU、内存这几项基础指标看过再做结论。6.5 802.1Q标签引发的问题汇总在VLAN相关问题上常见故障点可以列表说明现象可能原因排查手段同VLAN内设备互通正常跨VLAN不通三层接口或VLANIF没配置或VLAN间路由策略阻止确认交换机VLANIF地址、路由、安全策略Trunk口下某些VLAN不通对端Trunk口allowed vlan列表不一致或native VLAN不匹配两端核对trunk端口配置抓包看有无标签抓包看到帧不带标签但端口配置了trunknative vlan的帧不打标签确认native vlan配置是否一致大包不通、ping小包正常MTU未考虑VLAN标签或隧道开销分段测试MTU调整MTU或开启巨型帧VXLAN或其他叠加网络下带宽低物理链路MTU不足封装头导致IP分片设置底层MTU为1500封装头长度或启用巨型帧6.6 交换机端口镜像与抓包的常见误区在做帧分析时我们经常需要在交换机上配置端口镜像SPAN/ERSPAN把某端口流量复制到抓包主机。这里有三个极其容易踩的坑第一镜像口和被镜像口的协商速率和双工模式。镜像时交换机通常会把流量复制一份但如果在镜像口上协商速率不一致会丢包或出现乱序抓包结果不能反映真实情况。第二SPAN会复制出的是原始帧不一定带FCS。部分交换机会把FCS剥离后再传给抓包主机因为交换机的ASIC在收帧时已经把FCS消耗掉了。第三抓包主机的网卡如果开启了硬件卸载比如TCP校验和卸载checksum offload、LRO等可能出现看起来坏包很多但实际只是抓包工具对卸载后的包解析有误的情况。抓包时建议关闭网卡的offload功能或在Wireshark里启用校验和验证选项并确认实际计算的校验装置是否真实。6.7 关于Wireshark显示帧校验和的注意点Wireshark中帧校验和FCS的解析情况因捕获文件的来源而异。普通以太网捕获文件中FCS默认会被去掉因为网卡驱动通常会剥离它。某些抓包硬件或特定的捕获配置下FCS会被保留并显示为四个字节。因此如果你在Wireshark里看到帧长度比预想多了4字节先确认是不是FCS被保留了下来而不要急着认为收到了坏帧。不同抓包平台的这一行为不完全一致做帧长度统计时尤其要小心。7. 实战手动构造一个自定义帧并解析7.1 为什么需要手动构造帧在某些开发场景下比如编写以太网协议测试工具、模拟恶意报文做安全测试、调试自研通信协议直接通过原始套接字构造数据链路层帧会比用现成命令灵活得多。Linux下可以用AF_PACKET套接字实现这种能力我们在调试某些非标准协议时经常用到。7.2 一个Python构造以太网帧的示例我们以发送一个目的MAC为广播地址源MAC为00:11:22:33:44:55类型为0x0800负载内容为hello的以太网帧为例。Python里可以用socket的AF_PACKET选项来实现。import socket # 构造以太网帧 dst_mac b\xff\xff\xff\xff\xff\xff # 广播地址 src_mac b\x00\x11\x22\x33\x44\x55 # 自定义源MAC ether_type b\x08\x00 # IPv4协议类型 payload bhello frame dst_mac src_mac ether_type payload # 补齐最小帧长度帧长度至少64字节 frame b\x00 * (64 - len(frame)) if len(frame) 64 else b # 发送到指定的网络接口比如eth0 s socket.socket(socket.AF_PACKET, socket.SOCK_RAW) s.bind((eth0, 0)) s.send(frame) s.close()运行之后去抓包就能看到一个目的地址是广播源地址是00:11:22:33:44:55类型0x0800的帧。注意这里我们没有计算FCS绝大多数网卡会在发送时自动补上FCS所以只要帧长度合法就行。这个示例的核心思想是让你从代码层面理解帧头是纯手工拼接出来的字节序列每个字节的位置和含义都对得上号。7.3 用十六进制视角解读抓到的帧当你手动构造并抓到包后打开Wireshark的Packet Bytes面板看到的十六进制应该像是这样假设VLAN标签不存在ff ff ff ff ff ff 00 11 22 33 44 55 08 00 68 65 6c 6c 6f \_____________/ \_____________/ \__/ 目的MAC 源MAC 类型 payload hello这个结构虽然简单但是把一整副帧格式的图景全部串起来了先是对齐和前导部分然后是链路层地址再是协议类型最后才是用户数据。理解这个顺序之后VLAN标签无非就是在源MAC和类型之间插入了TPID、PCP/DEI/VID帧格式的整体逻辑就一通百通了。7.4 再进一步也可以构造带VLAN标签的帧扩展一下上面的思路往帧里加一个802.1Q标签只需在源MAC和类型字段之间插入4个字节。TPID是0x8100PCP和DEI共4比特通常写0VID共12比特假设VLAN 100。VID 100转十六进制是0x0064组合起来就是tpid b\x81\x00 tci b\x00\x64 # PCP000, DEI0, VID100 (0x64) frame dst_mac src_mac tpid tci ether_type payload这样构造的报文就是标准的VLAN帧。实际使用时收到这种帧的交换机会根据VID判断它属于哪个VLAN并据此做转发决策。理解了标签在字节流里的精确位置你在配置交换机、排查VLAN问题时心里就非常有数了。8. 一些深入数据链路层后才会知道的经验老实说数据链路层的帧格式本身并不复杂14字节的头部翻来覆去也就几个字段但它背后牵扯的概念——最小帧长、CRC校验、VLAN标签、MTU联动、巨型帧——每一个单独拎出来都能让工程师排查半天。我和朋友交流时提到最多的一句话是不要把帧格式当成考试知识点要把它当成排查故障的工具。当你能从Wireshark的十六进制视图里一眼看出这是个VLAN帧、那个帧的Type字段是ARP、某个帧的长度统计有蹊跷时你对网络数据流动的感知就完全不一样了。举一个最近的例子。同事负责的一套工控系统说两台设备偶尔通信超时网线、交换机、IP配置查了个遍都正常。我在抓包里发现设备A发出的一个UDP广播帧里以太网类型字段写了0x88A8而不是0x0800明显是某个嵌入式设备在拼接帧头时把QinQ的TPID当作类型填进去了。这种问题如果只依赖协议栈的封装逻辑是永远找不到的——必须去看到原始帧内容才能发现某个字段被固件写错了。这就是熟悉帧格式在实际工作中的价值。最后分享一个小技巧日常做网络抓包不用每次都打开Wireshark图形界面命令行里用tcpdump -XX就能同时看到十六进制和ASCII码非常方便对照帧结构如果想分析大量报文tshark配合显示过滤器比鼠标点击效率高得多。我个人习惯是把常用的一些解析命令写成一个shell脚本抓完首包马上就能统计出帧类型分布、VLAN分布、CRC错误等指标比肉眼翻包靠谱太多。帧格式这部分内容看一遍觉得简单但真正在排障中熟练运用需要靠一次次抓包、比对、验证来积累直觉。希望这篇能把你在数据链路层的认知往前推一步下次再遇到不明不白的网络异常能下意识地想起去看一眼帧头。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门