4. MMS消息结构:深入理解PDU

MMS消息,说白了就是一段精心打包的数据。我刚开始接触时,也觉得这东西挺玄乎。但拆开来看,无非就是两部分:消息头消息体。嗯,就像寄快递,有快递单(消息头)和包裹内容(消息体)。

核心概念:MMS PDU(Protocol Data Unit)是MMS消息的传输格式。它定义了消息在网络上怎么跑,以及接收端怎么解析。

MMS PDU 结构总览 消息头 (Header) • X-Mms-Message-Type • X-Mms-Transaction-ID • From / To • Subject • Content-Type • ... 其他控制字段 消息体 (Body) • 文本内容 (Text) • 图片 (JPEG, PNG, GIF) • 音频 (AMR, MP3) • 视频 (3GP, MP4) • 幻灯片 (SMIL) • 其他附件

4.1 消息头(Header)字段详解

消息头,就是MMS的身份证。我见过不少开发者在解析MMS时,头字段没处理好,结果整个消息都乱了。这里有几个关键字段,你想想看,少了哪个都不行。

字段名 类型 说明 必填
X-Mms-Message-Type Encoded String 消息类型(m-send-req, m-retrieve-conf等)
X-Mms-Transaction-ID Text String 事务ID,用于请求-响应配对
From Encoded String 发送方地址(手机号或邮箱)
To Encoded String 接收方地址列表
Subject Text String 消息主题
Content-Type Content Type 消息体内容类型(application/vnd.wap.multipart.related)
X-Mms-Message-Class Encoded String 消息等级(Personal, Advertisement, Informational等)
X-Mms-Expiry Value Length 消息过期时间
X-Mms-Delivery-Report Boolean 是否请求送达报告

我的经验:我个人习惯在解析消息头时,先检查 X-Mms-Message-Type。这个字段决定了后续怎么处理。比如收到 m-send-req,你就知道这是发送请求,需要返回 m-send-conf

4.2 消息体(Body)组成

消息体,就是MMS的「肉」。它可以是纯文本,也可以是多媒体大杂烩。我记得有一次项目里,用户发了一张2MB的图片,结果因为消息体太大,直接超时了。嗯,这里要注意MMS的大小限制。

消息体通常采用多部分MIME格式。说白了,就是把多个文件打包在一起,每个部分都有自己的Content-Type。

--boundary_12345
Content-Type: text/plain; charset=UTF-8
Content-ID: <text_part>

这是一条MMS消息,包含图片和音频。

--boundary_12345
Content-Type: image/jpeg
Content-ID: <image_part>
Content-Transfer-Encoding: base64

/9j/4AAQSkZJRgABAQEASABIAAD...(base64编码的图片数据)

--boundary_12345
Content-Type: audio/amr
Content-ID: <audio_part>
Content-Transfer-Encoding: base64

#!AMR\n...(base64编码的音频数据)

--boundary_12345--

避坑指南:我曾经遇到过一个问题——Content-ID重复了。结果接收端只显示了最后一张图片。每个附件的Content-ID必须唯一,建议用UUID或者时间戳+序号生成。

4.3 附件类型与编码

MMS支持的附件类型,其实挺丰富的。但并不是所有手机都支持所有格式。我建议你在开发时,先查一下目标设备的支持列表。

常见附件类型

  • 图片:JPEG(最通用)、PNG(支持透明)、GIF(支持动画,但注意大小)
  • 音频:AMR(语音专用,压缩率高)、MP3(音乐常用)、AAC(高质量)
  • 视频:3GP(MMS标准格式)、MP4(H.264编码,兼容性好)
  • 文本:纯文本(UTF-8编码)、SMIL(幻灯片布局)
  • 其他:vCard(联系人)、vCalendar(日程)

编码方式

MMS消息体中的附件,通常使用Base64编码。为什么?因为MMS传输层是文本协议,二进制数据必须转成文本才能安全传输。你想想看,如果直接传二进制,遇到特殊字符就乱套了。

// 伪代码示例:Base64编码附件
function encodeAttachment(fileData) {
    // 读取文件二进制数据
    byte[] data = readFile(fileData);
    
    // 转换为Base64字符串
    String base64Str = Base64.getEncoder().encodeToString(data);
    
    // 添加到消息体
    return base64Str;
}

关键点:编码后的数据大小会增加约33%。所以原始文件1MB,编码后大约1.33MB。这在计算MMS总大小时要算进去。

4.4 实际项目中的避坑指南

做了这么多年MMS,我踩过不少坑。这里分享几个最常见的,希望能帮你少走弯路。

  1. 附件大小限制:不同运营商限制不同,通常300KB-600KB。我建议控制在300KB以内,兼容性最好。
  2. 文件名编码:附件文件名如果包含中文,一定要用UTF-8编码。我曾经见过用GBK编码的,结果在iPhone上显示乱码。
  3. SMIL布局:如果你用SMIL做幻灯片,注意时间轴设置。我遇到过一张图片显示0.1秒,用户根本看不清。
  4. Content-Type匹配:消息头的Content-Type必须和消息体实际内容一致。否则接收端可能无法解析。

我的小技巧:在开发MMS客户端时,我习惯先写一个PDU解析器,把消息头和消息体分开处理。这样调试起来特别方便,哪里出问题一目了然。

好了,MMS消息结构就讲到这里。记住,消息头是骨架,消息体是血肉,两者缺一不可。下一节我们会聊MMS的发送流程,到时候你会看到这些PDU是怎么在网络上跑起来的。

专注资料整理