4. MMS消息结构:深入理解PDU
MMS消息,说白了就是一段精心打包的数据。我刚开始接触时,也觉得这东西挺玄乎。但拆开来看,无非就是两部分:消息头和消息体。嗯,就像寄快递,有快递单(消息头)和包裹内容(消息体)。
核心概念:MMS PDU(Protocol Data Unit)是MMS消息的传输格式。它定义了消息在网络上怎么跑,以及接收端怎么解析。
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,我踩过不少坑。这里分享几个最常见的,希望能帮你少走弯路。
- 附件大小限制:不同运营商限制不同,通常300KB-600KB。我建议控制在300KB以内,兼容性最好。
- 文件名编码:附件文件名如果包含中文,一定要用UTF-8编码。我曾经见过用GBK编码的,结果在iPhone上显示乱码。
- SMIL布局:如果你用SMIL做幻灯片,注意时间轴设置。我遇到过一张图片显示0.1秒,用户根本看不清。
- Content-Type匹配:消息头的Content-Type必须和消息体实际内容一致。否则接收端可能无法解析。
我的小技巧:在开发MMS客户端时,我习惯先写一个PDU解析器,把消息头和消息体分开处理。这样调试起来特别方便,哪里出问题一目了然。
好了,MMS消息结构就讲到这里。记住,消息头是骨架,消息体是血肉,两者缺一不可。下一节我们会聊MMS的发送流程,到时候你会看到这些PDU是怎么在网络上跑起来的。