☰
SMS与MMS技术详解:从信令原理到短信网关工程实践
2026/10/15 4:32:41 网站建设 项目流程

短信这个老朋友,很多人已经快忘了它的存在——日常聊天早就转移到了各种即时通讯软件上,但银行通知、验证码、航班提醒、快递取件码,几乎每一天仍然在通过短信悄悄抵达你的手机。尤其是做过移动端开发、物联网或者后台服务的人,一定绕不开SMS和MMS这对难兄难弟。这篇文章我想系统地把SMS和MMS背后的技术链路、协议原理、工程实现,连带着我这些年实际踩过的坑一起聊一遍。它适合正在对接短信网关的开发者、刚入门运营商网络领域的初学者,也适合那些想搞清楚“为什么一条短信只有160个字符”“为什么图片短信总是加载半天”的好奇读者。

1. SMS的背后:从信令网络到160个字符的秘密

1.1 SMSC、短信网关与信令链路

SMS全称Short Message Service,短消息服务。很多人以为短信是“走数据通道”发出去的,其实它最经典的形态走的是信令通道。手机开机后,会通过基站跟所在网络完成位置更新,这个信息会被登记到归属位置寄存器和访问位置寄存器上。你要发一条短信,手机先把消息发给基站,基站再把它转给当前网络里的移动交换中心,最终送到一个专门负责短信的网元——SMSC,短消息服务中心。

SMSC的角色就像短信界的邮局。它收到手机发来的短信后,会根据收件人的号码判断对方在哪个网络,如果对方暂时关机或者不在服务区,SMSC不会直接把消息丢掉,而是进入重试队列,等对方重新上线后再下发。这也解释了为什么手机一开机,往往能一次性涌进来好几条“迟到”的短信。

从协议层上看,SMS真正依附的是信令系统,早年间在GSM网络里靠的是7号信令系统的MAP协议,后来又逐渐迁移到IP化的信令承载上。理解这一点很重要,因为信令通道的带宽极其有限,这直接决定了短信必须用极其紧凑的方式编码,也决定单条短信的长度天然存在硬上限。

1.2 160个字符的限制来自哪里

“一条短信最多160个字符”是很多人听过却不知道原因的说法。答案跟一次短信最大能承载的数据量有关:SMS在GSM阶段规定,单条短信的用户数据部分最多是140字节。140字节如果按照7比特编码来折算,正好是160个7比特字符,因为160乘7除以8等于140。

所以160字符这个数字不是某个厂商拍脑袋想出来的,而是由140字节这个PDU限制推导出来的。所谓PDU,就是Protocol Data Unit,协议数据单元。短信内容在编码过程中要被封装成TPDU结构,加上各种头信息、地址信息、协议标识,最后塞进信令消息里传输。整条消息的可变长用户数据区被限制为140协议字节,内容一多就装不下。

这个限制带来的体验问题在当年尤其明显,手机编辑短信的时候,字数接近160会看到计数器警告,超过之后手机会自动把消息拆成多条发送,接收方通常看到的是收到的多条消息,但有些老手机甚至不支持重组显示。后来又出现了长短信技术,也就是利用用户数据头部的UDH段来标记“这是第几段的第几部分”,让手机把多条合并显示,这个技术我们后面专门讲。

1.3 编码:GSM-7、UCS-2与中文短信

短信在手机终端和网络之间传输,消息内容本身不是明文裸传的,而是要做字符编码。早期GSM网络定义了一套名为GSM 7-bit的默认字母表,里面包含了大写小写英文、数字、常见符号以及一些控制字符。这套字母表里的每个字符用7个比特表示,因此140字节最多能放160个字符。

但GSM 7-bit基本字符集本身是不含中文的。要想发中文短信,手机终端就必须切换到UCS-2编码,也就是每个汉字用2个字节表示。这样一来,140字节除以2,单条短信最多只能装70个字符。很多人发中文短信时会发现明明只写了几十个字却被算成两条,其实就是因为编码从7-bit切到了UCS-2,容量从160缩到70。

这里有个工程细节容易被忽视:一条短信到底用GSM-7还是UCS-2,不是只看内容里有没有中文。如果消息中包含了GSM 7-bit字符表之外的符号,比如某些特殊标点、emoji,终端或网关都会认为需要升级编码。而从GSM-7切换到UCS-2会导致整条消息的可用字符数急剧下降。更麻烦的还在后面,如果一个长短信的前半段用了GSM-7,后半段因为某个特殊符号不得不切成UCS-2,两段的分割点会在字节边界上错乱,导致部分老终端收到乱码甚至拒收,这个问题我在第四部分会展开。

2. MMS:当一条短信装不下图片时,真正的流程什么样

2.1 MMS不是“SMS加附件”,而是一个独立的媒体邮件系统

MMS全称Multimedia Messaging Service,多媒体消息服务。从用户视角来看,MMS就是能发图片、音频、视频、名片的多媒体短信。但从网络工程的视角看,MMS跟SMS走得完全是另一条路。

SMS走信令通道,数据量小、实时性强。MMS则被设计成一种“存储转发”的媒体消息系统,底层更像电子邮件。一条MMS消息本质上是一个由MIME格式封装的复合文档,里面可以包含一个或多个多媒体部件。它不直接通过信令通道传递内容,而是先把内容上传到MMSC,再由MMSC以通知的形式告诉接收方去下载。

所以与其说MMS是“SMS加附件”,不如说它是一套独立的消息平台:SMS负责的是那条“你有一条彩信”的触发通知,而真正承载图片、音频的是运营商部署的MMSC和WAP网关。理解这个结构,就能理解为什么MMS在网络信号不好的时候表现得比SMS糟糕得多。

2.2 “WAP PUSH”的引导与MMSC的转发机制

一条典型MMS发送的完整流程是这样的:

发送方通过手机编辑好多媒体内容,手机上装的MMS客户端会把消息封装成MMS PDU,然后通过HTTP或WAP协议上传到本运营商的MMSC。MMSC负责对消息做内容检查、格式转换、计费,然后解析接收方号码并判断接收方属于哪家网络。

如果接收方和发送方在同一家网络,MMSC可以直接把消息存下来。如果跨网,就需要两边的MMSC互相转发,这期间还会通过SMS信令交换路由信息。关键点来了:MMSC并不会直接把多媒体内容推给接收方,而是给接收方下发一条特殊的短信,这条短信从用户界面看往往显示为“收到一条彩信”或“中国移动/联通/电信彩信”,这就是WAP PUSH通知。接收方手机根据PUSH里携带的MMSC地址和消息标识,主动发起一个HTTP请求去把真正的内容下载下来。

这套机制的好处是接收到消息前并不占用数据流量下载完整内容,而是由通知驱动;坏处是步骤多,任何一环出了问题都会导致“彩信下载失败”的经典问题。

2.3 手机终端如何处理MMS的封装与提取

对开发者来说,如果想在自己的应用中解析MMS消息,就要跟MMS PDU格式打交道。MMS PDU本身是二进制的,但它的Message Type字段、Header字段、发送方地址、收件人地址、主题、附件类型都可以在头部区标识清楚。

一个MMS消息体在MIME层面通常是multipart/related结构,里面主媒体部件是指定的主题HTML或者纯文本,后面跟着一个个附件实体。终端收到后会先解析头部的事务ID和消息类型,再根据Content-Type判断这是通知消息、读取报告还是实体的数据消息。

我记得自己第一次尝试在模拟器上解析运营商发来的彩信时,被那头部的字节对齐折腾了很久。MMS PDU头每个字段都有固定的标识号,比如MMS Message Type是0x8C,From地址是0x89,To地址是0x97,Subject是0x96。调试的时候用十六进制把它们dump出来,对着规范手册逐字段解析,最能帮助理解这套协议的真实模样。

3. 运营商网络对SMS/MMS的现实制约与兼容性问题

3.1 到达率:为什么有时候短信会“丢失”

做短信业务的人最怕两件事:一是消息下发超时,二是消息无缘无故不见。绝大部分短信丢失问题,追根溯源是发生在SMSC到手机终端的下发阶段。

SMSC的短信下发流程类似于“先查询路由,再发送”。如果接收方当前附着在2G/3G/4G/5G任一网络下,系统会选择合适的信令通道把短信发到基站,基站再通过寻呼通知手机。手机收到后如果没有及时回复确认,网络侧会认为下发失败并进入重试流程。问题是有些网络在重试过程中会直接丢弃消息,或者把消息滞留在旧的位置区缓存里,导致接收方明明已经换了位置却再也等不到了。

另一个常见原因出在号码格式上。很多平台在向国际用户发送短信时,没能正确格式化号码为E.164格式。E.164要求号码带国家码,比如发往中国大陆的号码要写成+86开头,去掉前导0。格式一旦出错,SMSC可能把消息发给错误的国际网关,或者因为路由表匹配失败直接返回错误。

3.2 不同制式与终端的差异

SMS经过几十年的演进,在不同制式下的实现并不完全一致。GSM网络里短信走的是控制信道,CDMA网络里则使用类似于SMS over paging channel的方式,两个体系的短信消息格式和协议大致相似,但在长度限制、编码处理和状态报告实现上有不少差异。比如CDMA短信通常支持更长的单条消息,但某些终端的兼容性又不好。

现在5G网络已经大规模铺开。理论上,5G网络下短信依然通过NAS信令消息的SMS over NAS来传输,实际体验上延迟更低、成功率更高。但要注意的是,很多物联网模块和廉价智能终端对SMS的实现并不完整,比如不支持Concatenated SMS、不支持状态报告、无法解析NPI/TON地址类型等。在开发短信应用时,不能假设所有终端都跟旗舰手机一样聪明。

3.3 国际漫游与老旧的MMS实现

MMS在国际漫游场景下问题更明显。MMS的抓取链接往往使用运营商的私有域名或IP地址,漫游时终端不一定能连回归属地的MMSC。有些终端在漫游网络下甚至收不到WAP PUSH通知,或者收到通知后因为DNS解析失败导致下载不了。这也是为什么国际漫游时,用户经常出现“图片短信只能看到通知下载不了,或者要开着蜂窝数据等很久才能打开”的情况。

从我实际维护短信网关的经验来看,对MMS的处理要预留重试与降级机制。正常情况下,如果MMS下载失败,终端会提示“下载失败,是否重试”。这里终端不一定每次都会重新发起HTTP请求,有些实现会等待下一次WAP PUSH触发。作为平台方,最好的做法是在MMSC侧主动重推通知,而不是死等终端来下载。

4. 开发短信应用时我踩过的坑:编码、拆分、拦截与回复

4.1 长短信的巧妙处理与UDH头部分拆

前面提到SMS单条长度限制只有140字节。我们要给用户发一条服务通知,动辄几百字,怎么办?答案是使用长短信技术,也叫拼接短信。

长短信的原理是在用户数据前插入一段用户数据头(UDH),这段头里有一个信息元素标识符,用于标记长短信的标识、总条数和当前条序号。接收终端收到所有分片后,会根据这些信息把散片重新拼成完整消息。创建分组:ESME(外部短消息实体)发送长短信到SMSC时,通常将大消息拆分成较小的片段,每个片段包含相同的标识符和序号信息。

这个机制本身不复杂,但实操中容易踩到字节计算的坑。长短信的UDH通常占6到7个字节,具体看是否包含端口号等额外信息。UDH占掉用户数据长度后,GSM-7编码的单分片可承载的字符数不再是160,而是153;UCS-2编码则从70变成67。如果拆分代码只是简单按照“160个字符一秒分”去拆,长消息在接收方手机上就会出现乱序、缺段或乱码。

4.2 编码切换:GSM-7与Unicode切换时的字节界问题

这是我自己真实踩过最深的一个坑。当时运营后台要给一批用户发送通知,消息模板里既有中文又有英文标点。后台的短信拆分服务一开始只按字符数简单拆分,结果部分用户收到的长短信中间出现了乱码和空白段。

排查后发现,短信平台在处理长消息时,第一段使用了GSM-7编码,第二段因为某个字符使用了中文全角标点被迫切换到UCS-2,两个分片的编码不一致,导致接收方在拼接时无法正确对齐字节界。

正确做法是:在拆分前先对整个消息内容做一次字符集检测。要么全部使用GSM-7拆分并发送,要么一旦检测到任何超出GSM-7基础字符集中的字符,整条消息统一采用UCS-2编码拆分。绝对不要在一个长短信的不同分片里混用两种编码。这件事儿听着简单,但在自动生成的消息模板里很容易由于标点符号、特殊符号而变化,所以建议在消息进入发送通道前统一做一次规则化,把中文标点全部转换成对应英文符号,或者干脆全部按UCS-2处理。

4.3 发送失败码与常见排查路径

对接运营商短信网关时,失败码绝对是最能让人头疼的东西。不同厂商的回执码表达方式不同,但大致可以归成几类。

第一类是透明失败码,比如UnknowSubscriber,说明号码在运营商侧不存在或已销户。第二类是临时失败码,比如MemoryCapacityExceeded、EquipmentBusy、SMSRejected,这些往往因为终端侧内存满或暂时忙,等等。第三类是比较棘手的,比如MissingOrInvalidAck、DuplicateInvocation,这类通常说明我们在与网关交互的消息参数上出了问题。

排查发送失败问题,我的建议是分层看。先看基础回执有没有回来,如果连SubmitResp都没等到,说明是超时或连接层问题;再看状态报告里的详细失败码,确认问题来自HLR、MSC还是SMSC。最后别忽略号码本身的格式,很多所谓“发送失败”,都只是因为号码带了不规范的字符或者缺了国家码。

4.4 短信验证码应用中的时效、频率与反滥用

随着SMS在营销和等级保护中的键角,验证码、通知和双因子认证短信成为最常见场景。这类短信对时间非常敏感。设计验证码系统时,我通常会引入离站式生成:验证码在服务端生成,经过签名后在短信网关侧添加有效期和最大发送频率限制。不要在前端直接生成验证码再传给服务端,否则很容易被绕过。

短信接口在正式环境还需要考虑拦截和封禁策略。一般会用IP频率限制、手机号频率限制、时间段控制、模板匹配和内容敏感词过滤。尤其是营销类短信,平台往往要求内容中带“回复TD退订”等定制模板,实际对接时需要按运营商要求预处理文本内容,避免发送后被拦截或造成用户投诉。

5. MMS越来越稀少,但SMS还在战斗——聊聊RCS与未来

5.1 RCS的目标其实是把SMS升级到“消息即平台”

近几年行业里一直提RCS,富通信服务。简单说,RCS是希望把传统短信升级为支持群聊、文件传输、位置共享和对话机器人(Chatbot)的新一代消息服务。

从网络链路看,RCS消息走的是数据通道,而不是信令通道,所以支持更大的消息体、更强的媒体能力和更丰富的交互体验。MMS在这套新协议面前显得尤其笨重:MMS的消息大小往往被限制在KB级别,而RCS可以轻松支持几十MB的媒体文件。

但RCS的落地并不顺利,除了各厂商定制差异,还需要运营商投入大量网关和互通支持。即便到了今天,做跨运营商RCS互通的完整性仍然不如传统SMS。RCS更像是对SMS和MMS的形态升级,而不是简单替换。对普通用户来说,短信这个入口依然存在,只是背后的承载方式变了。

5.2 在调试和测试中,我最常用的工具与经验技巧

最后分享一些我平时调试SMS/MMS接口时的实用经验。

首先,尽量准备一张不限短信数量的测试卡。很多问题必须在真实网路环境下复现,比如长短信拼接、状态报告回执和编码转换,这些在模拟器里很多看不到。用测试卡配合一个能够支持AT指令的GPRS/4G模块,是排查终端层问题的最快方式。模块可以直接发送AT指令,比如AT+CMGF=1切换文本模式,AT+CMGS="号码"发送短信,AT+CNMI=2,1设置新短信通知URC方式,简单直接。

其次,在生产环境建一个独立的短信回执落库。每一条短信下发后,要记录提交时间、运营商回执码、状态报告是否返回。当业务方问“为什么用户没收到短信”时,这些数据就是证明链路真相的有力依据。没有这种日志,排查问题全靠猜,效率极低。

最后,不要把所有鸡蛋放在一个短信网关里。正规业务至少接入两到三家短信通道,做通道权重配置和自动降级。遇到通道拥堵、批量封禁或运营商升级时,备用通道能救命。

至于MMS,如果业务确实需要发送彩信,尽量提前跟运营商确认消息大小上限、支持的文件格式和下载服务器的超时策略。不同厂商对彩色图片的压缩策略差异极大,测试覆盖越多,后期投诉越少。


我自己的体会是,SMS这套技术虽然老旧,但它背后的信令网络、编码体系、重试机制和网关协议,依然是理解整个移动通信网络最干净的入口。你掌握了160字符的由来、UDH拆分规则和失败码排查思路之后,再去看RCS、VoLTE甚至5G消息,基本上都是同一套思维框架在应对不同的承载层。这个时代分布式系统、HTTP接口、微服务随处可见,但像短信这样从几十年前一路沉默稳定运行过来的基础设施,反而更值得花点时间把它背后的逻辑摸透。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询