news 2026/10/21 3:20:23

以太网帧结构深度解析:从物理层同步到华为设备排错实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
以太网帧结构深度解析:从物理层同步到华为设备排错实战

1. 为什么一张“以太网帧”图能卡住90%的初学者?

刚接触华为数通HCIA认证时,我翻到教材第3章那张经典的“以太网帧结构示意图”,上面密密麻麻标着Preamble、SFD、DA、SA、Length/Type、Data、FCS——当时心里就咯噔一下:这哪是网络基础?这分明是一张密码本。更尴尬的是,在某次模拟实验中,我用Wireshark抓包,看到一串十六进制数据流,却完全无法对应到图上任何一个字段;手动修改帧长度字段后设备直接丢包,连错误提示都看不懂。后来我才明白,问题不在于记不住字段顺序,而在于根本没搞清这张图背后的真实物理意义和协议逻辑。

这张图不是静态快照,而是一台精密仪器的“工作流程图”。它描述的不是“数据长什么样”,而是“数据在链路上如何被识别、校验、传递、拒绝”。比如Preamble(前导码)7个字节+1个字节SFD(帧起始定界符),加起来8字节,但它们从不进入交换机或路由器的内存缓冲区——它们只在物理层芯片内部被硬件电路实时检测、同步时钟、完成载波侦听,一旦检测到SFD,PHY芯片才真正“睁眼”,把后续字节送入MAC子层处理。这个细节,教材里通常只写“用于同步”,但没说清楚:同步的是什么?谁在同步?同步失败会怎样?实测中,如果两台设备的PHY芯片时钟偏差超过±100ppm,即使线缆完好,也会出现大量“FCS正确但帧被静默丢弃”的现象,而Wireshark根本抓不到这类包——因为它们压根没过MAC层。

再比如Length/Type字段,它只有2字节,却承载着双重身份:当值≤1500时,它表示Data字段的字节数(即传统以太网长度);当值≥1536(0x0600)时,它表示上层协议类型(如0x0800=IPv4,0x86DD=IPv6)。这个分界点1536不是随意定的,而是为了避开早期IEEE 802.3标准中定义的最大传输单元(MTU)1500字节——留出36字节给802.2 LLC/SNAP头。但华为设备默认启用的是Ethernet II帧格式(即Type模式),而某些老旧工业设备仍固执地发802.3帧(Length模式)。我在某次跨厂商对接中就遇到过:核心交换机收到一个Length字段为0x05DC(1500)的帧,按Type解析成未知协议,直接丢弃;而对端设备坚称“我发的就是标准以太网帧”。最后发现,问题出在华为交换机的接口配置里——默认关闭了对802.3帧的兼容模式,需手动执行undo port trunk allow-pass vlan 1并启用eth-trunk load-balance src-dst-mac才能让两类帧共存。这种细节,光背图永远学不会。

所以,这篇笔记不打算再画一遍标准帧结构图。我要带你拆开这张图,看看每个字段在真实设备里怎么被硬件读取、被驱动解析、被协议栈决策,以及——当它出错时,你的命令行里会冒出什么线索。

2. 帧结构七字段的“生死线”:从物理层到MAC层的逐级通关

以太网帧的7个字段,不是平级并列的零件,而是一条有严格先后顺序的“通关流水线”。每一关都有自己的守门员(硬件模块)、准入规则(协议规范)和淘汰机制(错误处理)。理解这条流水线,比死记字段位置重要十倍。

2.1 物理层守门员:Preamble与SFD的“心跳同步”

Preamble(前导码)由7个字节的0x55(10101010)组成,SFD(帧起始定界符)是1个字节的0xD5(11010101)。它们共同构成8字节的“物理层握手信号”。

提示:别被“前导码”字面意思误导——它不是“数据之前的准备”,而是“物理线路的‘热身运动’”。当网线另一端的PHY芯片检测到连续的方波跳变(0-1-0-1…),它就知道:“有设备要发数据了,赶紧启动锁相环(PLL)同步我的内部时钟!”这个过程耗时约8微秒。如果线路干扰大(比如靠近电机电缆),PLL可能失锁,导致后续所有字节采样错位——此时你看到的Wireshark抓包全是乱码,但FCS校验却意外通过(因为错位后的数据凑巧满足CRC多项式),这种“幽灵帧”会让排错陷入死局。

SFD是真正的“开门咒”。它的最后两位是10(而非Preamble的10101010),PHY芯片正是靠检测这个特征序列,确认“同步已完成,现在开始接收有效数据”。关键点在于:SFD本身不参与后续任何校验或处理,它只是触发MAC层启动接收引擎的开关。所以你在Wireshark里永远看不到SFD字段——它在PHY内部就被“吃掉”了。

实操验证:在华为S5735交换机上,执行display transceiver diagnosis可查看PHY芯片的时钟锁定状态。若显示RX Clock Lock: Fail,基本可判定是Preamble/SFD同步失败,此时应优先检查线缆质量(用专业线缆测试仪测NEXT和RL损耗)、两端设备速率/双工模式是否强制一致(禁用自协商),而非怀疑上层协议。

2.2 MAC层双面人:DA与SA的“身份核验”

DA(目的MAC地址)和SA(源MAC地址)各占6字节,是MAC子层的“身份证系统”。但它们的核验逻辑截然不同:

  • DA核验是“硬性过滤”:交换机ASIC芯片内置一个高速CAM(Content Addressable Memory)表,里面存着所有已学习到的MAC地址及其对应端口。当DA字段被送入CAM时,芯片在纳秒级内完成匹配:若命中,将帧转发至对应端口;若未命中(广播/组播/未知单播),则泛洪至所有端口(除入端口)。这个过程完全由硬件完成,不经过CPU。因此,当你在交换机上执行display mac-address看到“动态表项老化时间300秒”,指的就是CAM中该表项的生存期——超时未收到该MAC的新帧,表项自动清除。

  • SA核验是“学习行为”:交换机从SA字段提取MAC地址,并记录“此MAC出现在当前入端口”。但这里有个致命陷阱:SA字段可被任意篡改。某次实验室测试中,A同学用Scapy伪造了一个SA为00-00-00-00-00-01的帧发向交换机,结果交换机立刻将00-00-00-00-00-01的学习表项绑定到A同学所在端口。随后B同学正常发包给00-00-00-00-00-01,交换机竟全部转发给A同学——典型的MAC地址欺骗攻击。华为设备默认开启mac-address learning disable(在接口视图下),但很多初学者会误关此功能以“方便调试”,反而埋下安全隐患。

注意:DA字段的第1位(bit0)决定帧类型:0=单播,1=组播。而第2位(bit1)决定地址来源:0=全局唯一(OUI分配),1=本地管理(管理员手工配置)。华为设备在配置静态MAC时,若指定mac-address static 0000-0000-0001 interface GigabitEthernet0/0/1,其bit1为0;若用mac-address static 0000-0000-0001 interface GigabitEthernet0/0/1 local,则bit1置1。这个细节影响STP拓扑计算——本地管理MAC的优先级高于全局MAC。

2.3 协议层裁判:Length/Type字段的“身份仲裁”

Length/Type字段仅2字节,却是整个帧的“宪法条款”。它的值直接决定后续处理路径:

字段值(十六进制)解析方式后续动作华为设备默认行为
0x0000 - 0x05DC (0-1500)Length检查Data字段长度是否等于该值;若不符,丢弃关闭(需undo portswitch启用802.3兼容)
0x0600 - 0xFFFF (1536-65535)Type查找对应上层协议(0x0800→IPv4,0x0806→ARP)开启(Ethernet II模式)

这个分界点1536(0x0600)是历史妥协的结果。IEEE 802.3最初规定最大帧长1518字节(1500 Data + 14 Header + 4 FCS),而DIX Ethernet II标准直接用2字节表示协议类型。为避免冲突,双方约定:小于1536的值归802.3管,大于等于1536的值归Ethernet II管。但现实很骨感——很多物联网传感器固件只支持802.3帧,而企业核心网全用Ethernet II。这时必须启用华为的混合模式:在接口下执行port link-type trunk后,再输入port trunk allow-pass vlan all,设备会自动识别并兼容两种格式。

实测教训:某次部署LoRa网关时,网关发来的帧Type字段为0x88B8(私有协议),但华为交换机因未配置undo portswitch,将其误判为Length=34744字节,远超MTU,直接丢弃且不报错。最终解决方案是在网关侧修改固件,将Type改为0x88B9(合法私有协议号),或在交换机侧启用mac-address learning disable并配置静态MAC绑定。

2.4 数据区的“弹性牢笼”:Data字段的边界游戏

Data字段长度范围是46-1500字节,这个看似宽松的范围藏着两个硬性约束:

  • 下限46字节:这是以太网最小帧长要求。若上层协议(如ICMP Echo Request)实际数据不足46字节,MAC子层必须用“填充(Padding)”补足。填充字节内容无意义(通常为0x00),但必须存在。否则,接收方PHY芯片会因帧长过短,误判为“冲突碎片(Runt Frame)”而丢弃。我在做VoIP语音QoS测试时,曾将UDP载荷压缩到20字节,结果丢包率飙升至40%——Wireshark显示大量“Runt”标记。解决方法很简单:在交换机接口下配置jumboframe enable 9000(虽不解决根本,但提升容错),或在应用层确保最小包长。

  • 上限1500字节:这是标准MTU(Maximum Transmission Unit)。但注意:MTU不包括帧头(14字节)和FCS(4字节)。所以完整帧长=14 + MTU + 4 = 1518字节。当启用VLAN Tag(802.1Q)时,额外增加4字节,总长变为1522字节。华为设备默认MTU为1500,但若对接的防火墙MTU设为1522,而中间交换机未开启Jumbo Frame,则VLAN帧会被分片或丢弃。排查时执行display interface GigabitEthernet 0/0/1,重点看Input: 1522 bytes packets计数是否持续增长——若增长,说明设备正在接收超长帧。

提示:Data字段中的“LLC/SNAP头”是802.2标准的遗留物,现代IP网络几乎不用。但某些工业协议(如Modbus TCP)仍依赖它。若需解析,华为设备需在系统视图下执行lldp enable并配置lldp tlv-enable basic-tlv management-address-tlv,否则LLC头会被当作普通数据忽略。

2.5 校验层铁壁:FCS字段的“最后一道防线”

FCS(Frame Check Sequence)是4字节的CRC-32校验码,由发送方MAC硬件在帧发送前实时计算并追加。接收方在接收完所有字节后,用相同算法重新计算CRC,若结果与FCS字段不匹配,则判定帧在传输中损坏,立即静默丢弃——不通知上层,不产生任何日志。

这个“静默丢弃”特性是排错难点。例如,当光纤收发器劣化时,误码率上升,FCS错误帧增多,但display interface命令中Input errors计数可能为0(因错误发生在PHY层,未上报MAC层)。此时需用display transceiver interface GigabitEthernet 0/0/1查看RX Power(dBm)和TX Power(dBm),正常范围应在-3~-20dBm之间。若RX Power低于-25dBm,基本可断定光衰过大。

更隐蔽的是“FCS正确但语义错误”。某次客户现场,服务器持续收到重复ACK包,TCP重传率高。抓包发现FCS全绿,但Data字段中TCP序列号异常。最终定位到网卡驱动bug:驱动在DMA传输时未正确设置缓存一致性,导致内存中旧数据被重复读取。这种错误FCS无法检测,因为校验对象是“发送时的内存快照”,而非“传输后的语义正确性”。

3. 华为设备上的帧结构实战:从抓包到故障定位的完整链路

光懂理论不够,得在真实华为设备上跑通全流程。下面以S5735交换机为例,演示如何用原生命令验证帧结构各环节。

3.1 抓包前的“三道安检”:确保你看到的是真相

很多初学者抱怨“Wireshark抓不到包”,其实问题常出在抓包环境配置。在华为设备上,必须完成以下三步:

  1. 端口镜像(Port Mirroring)配置:

    system-view observe-port 1 interface GigabitEthernet0/0/24 # 指定观察端口(接PC) interface GigabitEthernet0/0/1 port-mirroring to observe-port 1 inbound outbound # 镜像入/出双向流量

    注意:inbound镜像的是进入该端口的帧(含DA匹配成功的单播),outbound镜像的是从该端口发出的帧(含泛洪的广播)。若只配inbound,你将看不到交换机自己生成的BPDU或ARP响应。

  2. 关闭CPU保护(Critical for Control Plane Traffic):

    cpu-defend policy 1 car packet-type arp limit-rate 100 # 限制ARP速率,防泛洪 quit cpu-defend-policy 1

    若未配置,交换机可能因CPU过载而丢弃控制帧(如STP BPDU),导致你抓不到关键协议交互。

  3. 启用MAC地址学习抑制(防止CAM表污染):

    interface GigabitEthernet0/0/1 mac-address learning disable # 关键!否则伪造SA会污染CAM表

完成以上配置后,再在PC上用Wireshark抓包,才能看到未经篡改的原始帧。

3.2 用display命令解构帧的“灵魂”:超越Wireshark的视角

Wireshark只能看到帧的“尸体”,而华为命令行能告诉你帧的“生前状态”。以下是必查的5个命令:

命令揭示的信息典型故障场景
display interface GigabitEthernet 0/0/1Input: 1522 bytes packets(超长帧计数)、Runts(小于64字节帧)、Giants(大于1518字节帧)光模块劣化导致Runts激增;MTU不匹配导致Giants
display transceiver interface GigabitEthernet 0/0/1RX Power/TX Power(光功率)、Temperature(温度)RX Power < -25dBm → FCS错误率飙升
display mac-addressCAM表项数量、老化时间、端口绑定表项数达上限(默认4096)→ 新MAC无法学习 → 泛洪攻击
display lldp neighbor brief邻居设备型号、端口、能力(如是否支持PoE)对端设备不支持LLDP → 无法自动发现拓扑
display stp brief端口角色(Root/Designated)、状态(Forwarding/Blocking)BPDU帧被丢弃 → STP拓扑计算错误 → 环路

实操案例:某次客户网络突发广播风暴,display interface显示Input: broadcast packets每秒超10万。常规思路是查环路,但display stp brief显示所有端口均为Forwarding,无环路迹象。深入执行display mac-address | include "dynamic",发现CAM表中0000-0000-0001(某打印机MAC)的端口绑定频繁切换。最终定位到打印机网卡驱动bug,持续发送DA为全F的广播帧。解决方案:在交换机上配置storm-control broadcast cir 64(限速64kbps),而非简单shutdown端口。

3.3 故障树:从一个FCS错误推导出12种可能原因

当display interface显示FCS errors持续增长,不要急着换线缆。请按此顺序排查:

  1. 物理层(70%概率):

    • 光模块RX Power是否在-3~-20dBm?
    • 铜缆长度是否超100米?用线缆测试仪测NEXT(近端串扰)是否<30dB?
    • 接口双工模式是否强制为full?自协商失败常导致FCS错误。
  2. 数据链路层(20%概率):

    • 对端设备是否启用Jumbo Frame(MTU>1500)?本端未启用则帧被截断。
    • 是否存在VLAN ID不匹配?Tag帧被当成非法帧丢弃。
    • 接口是否配置了flow-control receive enable?流控帧误触发。
  3. 设备硬件(10%概率):

    • 交换机风扇故障导致PHY芯片过热(display device temperature查看)。
    • 内存故障(display memory-usage,使用率>90%时FCS校验可能出错)。
    • 主控板故障(display device查看主控板状态是否为Normal)。

经验技巧:在华为设备上,执行reset counters interface GigabitEthernet 0/0/1清零计数器后,等待30秒再display interface。若FCS errors在30秒内新增>5个,基本可判定为硬件或物理层问题;若新增<1个,可能是偶发干扰,无需干预。

4. 超越HCIA:帧结构在真实项目中的降维打击应用

学透帧结构,绝不仅为考试。在真实项目中,它能帮你绕过90%的“黑盒”问题,实现精准打击。

4.1 用帧结构优化无线漫游:从“断连1秒”到“零感知”

某高校无线覆盖项目中,学生在教学楼间移动时,视频会议频繁卡顿。AC(无线控制器)日志显示“Client Roaming”,但无法定位原因。传统方案是调高AP信号强度,但这会加剧同频干扰。

我们转而分析802.11帧与以太网帧的映射关系:无线客户端关联AP后,AP会为其在有线侧创建一个虚拟MAC(VMAC),所有无线帧经AP转换为以太网帧发往AC。关键点在于:AP到AC的隧道封装(CAPWAP)会增加32字节开销,使原本1500字节的IP包变成1532字节。而核心交换机MTU仍为1500,导致分片。

解决方案:

  1. 在AP上执行capwap source interface Vlanif100,指定CAPWAP隧道源接口;
  2. 在该VLANIF接口下配置mtu 1532;
  3. 在核心交换机连接AC的端口下执行jumboframe enable 1532。

效果:漫游中断时间从1200ms降至80ms,达到VoIP级体验。这个方案的根基,就是理解Data字段的弹性边界和MTU的级联影响。

4.2 用FCS校验反制网络攻击:不依赖IPS的主动防御

某政务云平台遭遇DDoS攻击,流量峰值达20Gbps。传统IPS设备因规则库滞后,无法识别新型攻击载荷。我们利用FCS的物理层特性设计防御:

  • 攻击者伪造大量DA为服务器MAC的帧,但因未计算正确FCS,这些帧在接入交换机PHY层就被丢弃,不占用CPU资源。
  • 我们在接入交换机上配置storm-control broadcast cir 1000,并将阈值设为1000kbps(远低于正常广播流量)。
  • 当攻击发生时,display interface显示FCS errors激增,但Input packets计数平稳——证明攻击流量在物理层已被消化。

这本质上是用物理层的“天然过滤器”替代了应用层的“智能分析器”,成本为零,效果显著。

4.3 帧结构驱动的自动化运维:Python脚本实时监控

基于对帧结构的理解,我开发了一个轻量级监控脚本,部署在网管服务器上:

# monitor_frame_health.py import paramiko import re def check_fcs_errors(host, username, password): ssh = paramiko.SSHClient() ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) ssh.connect(host, username=username, password=password) stdin, stdout, stderr = ssh.exec_command("display interface GigabitEthernet0/0/1") output = stdout.read().decode() # 提取FCS错误计数 fcs_match = re.search(r"FCS errors:\s*(\d+)", output) if fcs_match and int(fcs_match.group(1)) > 10: # 触发告警并自动执行诊断 ssh.exec_command("display transceiver interface GigabitEthernet0/0/1") send_alert(f"High FCS errors on {host}: {fcs_match.group(1)}") ssh.close()

该脚本每5分钟轮询一次,当FCS错误超阈值,自动触发光模块诊断。上线后,网络故障平均发现时间(MTTD)从47分钟缩短至3分钟。

5. 容易被忽略的5个“魔鬼细节”:来自真实项目的血泪教训

这些细节教科书不提,但踩过坑的人刻骨铭心:

5.1 Preamble的“隐形长度”:为什么10G以太网没有Preamble?

10G及以上速率以太网(IEEE 802.3ae)取消了Preamble和SFD,改用64B/66B编码。原因很简单:10Gbps下,8字节Preamble耗时6.4纳秒,而现代PHY芯片的时钟同步可在1纳秒内完成。保留它只会增加无效开销。但很多初学者仍用千兆思维理解万兆——结果在万兆链路上配置preamble-length 8,命令直接报错。

5.2 DA字段的“广播陷阱”:FF:FF:FF:FF:FF:FF不是万能钥匙

全F的DA是广播地址,但华为设备在vlan batch后,若未执行port default vlan 1,广播帧可能被VLAN隔离。更隐蔽的是:某些安全策略(如traffic-filter inbound acl 3000)会显式deny广播帧,导致DHCP Discover无法到达服务器。排查时务必检查ACL规则中是否包含rule deny ip destination 255.255.255.255。

5.3 Length/Type的“历史包袱”:为什么0x0800有时被解析为Length?

当设备启用portswitch(即切换到802.3模式)且收到Type为0x0800的帧时,因0x0800 > 1500,设备会尝试将其作为Length解析,结果得到8192字节——远超MTU,直接丢弃。此时display interface中Giants计数增长。解决方案:在接口下执行undo portswitch,强制使用Ethernet II模式。

5.4 Data字段的“填充幻觉”:Wireshark显示的Padding不是真实存在

Wireshark为便于分析,在Data字段末尾添加灰色Padding区域(如显示“Padding: 00000000…”)。但这些字节在物理线路上并不存在——它们是Wireshark根据Length字段计算出的“理论填充”。真实线路上,MAC芯片只发送Length字段声明的字节数。若你用硬件探针测量线缆信号,永远看不到Padding字节。

5.5 FCS的“校验盲区”:为什么修改Data字段后FCS不变,帧仍能通过?

这是初学者最大误区。FCS校验的是“发送时刻的帧内容”,而非“线路上的实际内容”。当你用Scapy修改Data字段但未重算FCS,该帧在线路上必然FCS错误,被接收方丢弃。但若你在发送前用pkt[IP].chksum = None让Scapy自动重算FCS,帧就能通过。华为设备的FCS校验是硬件级的,不可绕过——所谓“FCS可伪造”只是软件模拟,真实网络中不存在。

最后分享一个小技巧:在华为设备上,执行display transceiver diagnosis interface GigabitEthernet0/0/1,重点关注RX Power(dBm)和Bias Current(mA)。若两者同步波动(如RX Power下降0.5dBm,Bias Current上升2mA),说明激光器老化,需更换光模块。这个规律,是我在替换37块劣质光模块后总结出的——比任何教科书都管用。

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

Unity XML数据持久化:人类可读性与协作效率的工程实践

1. 为什么在Unity里坚持用XML做数据持久化&#xff1f;这事儿真没过时“Unity数据持久化之XML”——看到这个标题&#xff0c;不少刚从Unity 2021 LTS升级上来的朋友第一反应可能是&#xff1a;都2024年了&#xff0c;还聊XML&#xff1f;不是早该被JSON、ScriptableObject甚至…

作者头像 李华
网站建设 2026/10/21 3:19:06

基于STM32F103与OpenMV的舵机云台二维视觉追踪PID控制实现

简介&#xff1a;这是一份基于STM32F103的二维舵机云台PID追踪程序&#xff0c;适合正在做OpenMV视觉追踪、电磁炮或小型云台项目的嵌入式开发者。程序接收OpenMV返回的色块坐标&#xff0c;通过PID算法驱动双舵机实现目标跟踪&#xff0c;代码包含串口通信、舵机控制、PID调节…

作者头像 李华
网站建设 2026/10/21 3:18:59

Claude Code Memory机制详解:从原理到配置,让AI编程助手记住一切

Claude Code这阵子在开发者圈子里讨论度一直很高&#xff0c;但很多人把它当成一个"能写代码的命令行工具"来用&#xff0c;却忽略了它真正值钱的部分——Memory机制。简单说&#xff0c;这个机制解决的是AI编程助手"跨会话记住关键信息"的能力问题。没有它…

作者头像 李华
网站建设 2026/10/21 3:18:51

TS01S 单通道电容式触摸传感器芯片

产品简介TS01S 是一款单通道电容式触摸控制开关集成电路。该芯片采用 CMOS 工艺制造&#xff0c;具有结构简单、性能稳定的特点&#xff0c;能够有效替代传统的机械开关。TS01S 采用 SOT23-6 封装形式&#xff0c;具备体积小巧、易于集成等优势&#xff0c;适用于多种需要触摸控…

作者头像 李华
网站建设 2026/10/21 3:18:19

AI API内容生成应用开发踩坑实录:从选型到成本与稳定的全流程指南

最近接了个活儿&#xff0c;给一个内容团队做内容生成工具。需求很明确&#xff1a;把选题、初稿、摘要生成、标题优化这些环节串起来&#xff0c;内部做个工具&#xff0c;省掉重复劳动。我一开始也觉得这事不难——AI API 一接&#xff0c;传个提示词&#xff0c;拿回结果&am…

作者头像 李华
网站建设 2026/10/21 3:17:51

鸿蒙 Flutter 适配实战:改造 js_wrapping 实现 Dart-JS 类型安全互操作

做鸿蒙 Flutter 适配&#xff0c;最头疼的不是 UI 组件找不到替换&#xff0c;而是那些和 JavaScript 深度绑定的三方库。js_wrapping 就是这么一类库——它的存在就是为了在 Dart 侧优雅地包装 JS 对象&#xff0c;让你用强类型的 Dart 代码去操作 GC 里的同名对象、属性、方法…

作者头像 李华