什么是 SMPP?企业短信背后的那条长连接

不用术语讲 SMPP:绑定、窗口、PDU 与回执路径,以及为什么在高吞吐场景里连接形态本身很重要。

practitioner · 4 分钟阅读 · 第 2 / 8

SMPP 是平台与短信中心之间交换短消息的协议,跑在一条持续打开的会话上。绑定声明方向,会话带着吞吐窗口,送达回执以 PDU 返回。它不是一问一答的 API。

要点

  • SMPP 是一条持续打开的会话,绑定时声明方向。
  • 一个绑定承载一份吞吐配额和一个在途请求窗口。
  • 一条 PDU 有 16 字节头部,报文体随命令而变。
  • 送达回执异步返回,按 message ID 匹配。

是会话,不是一次调用

SMPP 在您的平台和短信中心之间保持一条连接。平台认证一次,声明要做什么,之后就在同一条会话上提交消息、接收事件。短信中心不必等新的请求才发回执或上行的短信。有结果要报时,它直接推一条 PDU 过来。

这种形态适合稳定的流量。会话状态已经建好,回执通道也一直开着,单条消息的开销就小。代价是客户端要自己管状态:绑定是否正常、在途窗口用了多少、心跳什么时候发、断线后怎么重连。这些在 HTTP 客户端里都不存在。

绑定声明方向

绑定就是通过认证的会话加一个方向。发送绑定(transmitter)用来提交消息,接收绑定(receiver)用来接收手机发起的消息和回执,收发绑定(transceiver)在一条会话里兼顾两者。服务商为每种绑定发凭据,也可能限制您能开几条。

扩容靠加绑定,不是把一条绑定推到配额之外。一条绑定对应一份吞吐配额和一个在途窗口。峰值不够,就再申请一条绑定,把流量摊开。一条绑定被推过窗口,换来的只会是限流、超时和重试。看起来像网络故障,根子在客户端。

绑定、提交、回执

  1. 应用(ESME)
  2. bind_transceiver 建立会话
  3. SMSC
  4. submit_sm_resp 已受理
  5. 送达回执
会话只开一次,每次提交拿到带 message ID 的响应,回执稍后沿同一条会话返回。 来源: smpp.org:SMPP 会话与 PDU 操作
文字说明

应用打开绑定,短信中心返回响应。应用用 submit_sm 提交一条短信,收到带 message ID 的 submit_sm_resp。稍后短信中心发来 deliver_sm,里面是送达回执。应用用 deliver_sm_resp 确认。工作结束后发送 unbind,关闭会话。

窗口就是约定

窗口是客户端在等待响应之前可以同时在途的请求数。它不是建议值。发得比窗口多,短信中心就限流。限流后还按原速率重试,队列只会越积越长。每次提交都要读响应码,遇到限流就降速,等窗口排空再发下一波。

心跳用来确认会话还活着。从不发 enquire_link 的客户端,可能一直挂在一条已经死掉的连接上,直到第一次提交失败才发现。每次掉线都立刻重连的客户端,又会压垮服务商。要退避重连、限制重连频率,并在绑定中断超过业务可承受时间时告警。

一条 PDU,逐字段拆开

command_length
53
command_id
0x00000004
command_status
0x00000000
sequence_number
1
service_type
source_addr_ton
1
source_addr_npi
1
source_addr
12345
dest_addr_ton
1
dest_addr_npi
1
destination_addr
15551234567
esm_class
0x00
protocol_id
0x00
priority_flag
0
schedule_delivery_time
validity_period
registered_delivery
0x01
replace_if_present_flag
0x00
data_coding
0x00
sm_default_msg_id
0x00
sm_length
4
short_message
54657374
文本
Test
头部固定,报文体随命令而变。submit_sm 带地址、编码和回执标志。 来源: SMPP v3.4 规范:PDU 头部与 submit_sm
文字说明

每条 PDU 都以四字节命令长度、四字节命令 ID、四字节命令状态和四字节序列号开头,后面是报文体。submit_sm 的报文体包括源地址、目的地址、短消息、数据编码和回执标志。可选参数以标签-长度-值字段传送。

一条短信的一天

客户端打开收发绑定,读取绑定响应。它提交一条短信,把响应里的 message ID 存下来。短信中心把短信路由到目的网络。几分钟后,一条 deliver_sm 带回回执:原始 message ID、状态,往往还有网络错误码。客户端确认回执,把状态和自己的记录对上。

每一步都有失败方式。凭据不对或接口版本不对,绑定会被拒。提交可能被限流、被拒绝,也可能先受理、后面在回执里失败。回执可能在验证码过期之后才到。客户端要存 message ID,能接受迟到的回执,并把应用自己的状态当作“用户做了什么”的准绳。

SMPP 与 DLR 错误码解码

解码器在浏览器里运行,粘贴的回执不会离开本页。

粘贴 command_status、送达回执的 stat/err 字段或十六进制 PDU,查看含义与排查方向。

sample
id:0123456789 sub:001 dlvrd:001 submit date:2610181200 done date:2610181201 stat:DELIVRD err:000 text:您的验证码是 123456
打开工具

先解码回执,再怀疑路由

把一条送达回执粘进 SMPP 与 DLR 解码器,逐字段读。看 message ID、状态、完成时间和错误码。状态不是 DELIVRD 时,错误码要对照服务商的代码表来读,可据此判断是号码、手机还是网络拒绝了这条短信。先做这一步,再让服务商改路由。

回执与排障

回执是异步的,以 deliver_sm PDU 的形式回到会话上,格式取决于短信中心。较新的实现把状态放在 message_state 这个标签-长度-值字段里。较旧的实现把文本回执放进短消息字段,用 id、stat、err 这样的键值对表示。两种都要能解析,不能只认一种。

按 message ID 匹配,不要按到达顺序。相隔一秒提交的两条短信,回执可能倒着回来,重试还可能产生重复。提交时存下 ID,回执到达时更新记录。同一个 ID 的第二条回执只有状态更新时才采纳。接入指南把这套做法写成了一份操作顺序。

检查一下

  1. 为什么再加一条绑定,比提高重试速率更有用?

    一条绑定只有一个窗口。加绑定是加容量,对着满窗口重试,只会增加排队和延迟。

  2. message ID 从哪里来?

    短信中心在 submit_sm_resp 里返回。存下它,之后按这个 ID 匹配回执。

  3. “已送达”的回执能证明什么?

    证明网络已接受并把短信送到手机方向,不证明有人读过。

答案按需展开。不评分、不存储、不外传。

常见问题

刚开始就必须用 SMPP 吗?

不必。HTTP 一个下午就能接好。流量稳定到值得维护一条会话时,SMPP 才划算。

什么是绑定?

一条持续打开的会话,加上声明的方向:发送、接收或收发。它承载吞吐配额,靠心跳保持打开。

什么是 PDU?

协议数据单元,SMPP 交换的二进制消息。每条 PDU 有 16 字节头部,报文体随命令而变。

可以走公网用 SMPP 吗?

通常可以,配合 TLS 和 IP 白名单,但要问服务商。有些部署会用专线。

长短信怎么处理?

可以用带用户数据头的拼接分段,也可以用网络负责分段的 payload TLV。最终要在手机上验证。
  • 用 SMPP 和 HTTP 接入短信

    把测试路由带到生产而不弄坏绑定、窗口和回执:绑定状态、吞吐、心跳、编码、回调与故障处理。

  • RFQ 与 RFP 模板包

    短信批发、eSIM 与数据、物联网与中国连接的字段清单,以及可在线作为 RFQ 发送的清单。

  • 路由测试样例报告

    脱敏的静态路由测试报告样例:路由测试检查什么、失败如何呈现,以及什么会触发路由复核。

把结论用起来

告诉我们流量、目的地和需要的测量项,我们会回复下一步。