短信的通信协议从 2G 时代一直到现在基本没有什么变化。
- 支持 140 个字节(140 Byte = 140 * 8 bit = 1120 bit)
- 支持 GSM-7 编码,8bit 编码,UCS-2 编码
- GSM-7 每个字符 7 bit,支持英语和西欧语言,配合 National Language Shift Table 功能,能够支持一些其他字母文字的语言。
- UCS-2 每个字符 2 Byte(16 bit),传递一些 GSM-7 框架不支持的语言,比如中文(字符太多,7bit 方案反倒不合适)。
- 8bit 用来传递图片等二进制数据。
- 根据短信协议,如果长度超出范围,需要在短信前面加上一个二进制头部,叫做 UDH(User Data Header)。
- UDH 一共 6 个字节
- 包含一些 SMS 拓展字段
- 对于短信拆分来讲,里面有这一批短信的总条数,和当前这条短信的序号
所以,
- 如果是中文短信,用 UCS-2 编码,每个字符 2 Byte,一条短信最长支持 70 个中文字符(140 Byte / 2)。
- 注意:所有字符,包括 ASCII 中的英文、数字、半角的标点,全部需要转换成 UCS-2 的 2 Byte 编码。
- 如果长于 70 个字符,就需要切割成多条,UDH 头部需要 6 Byte,每条短信还剩 134 Byte,除以二,还能装 67 个字符。
- 例如:140 个中文字符的短信,需要切割成 67 + 67 + 6 三条短信。
- 如果是英文短信,或者部分西欧语言,可以使用 GSM-7 编码,每个字符 7 bit,一条短信最长支持 160 个字符(1120 bit / 7)。
- 如果长于 160 个字符,也是需要切割,除去 UDH 的 6 Byte = 6 * 8 bit = 48 bit,还剩 1120 bit - 48 bit = 1072 bit,
1072 bit = 7 bit * 153 + 1 bit,也就是说最多发送 153 个字符(多的那 1 bit 置 0,不参与计费)。 - 例如,320 个英文字符,需要切割成 153 + 153 + 14 三天短信。
- 注意:GSM-7 编码中,9 个拓展字符
^ ~ \ | { } [ ] €
需要算两个字符。非常重要 - 数据通信中都是使用 Byte 为单位,用 GSM-7 编码可能会除不尽,也就是说剩余 1 ~ 7 bit。比如:
- 发送 33 个字,33 * 7 bit = 231 bit,需要 29 Byte (232 bit) 来装,就多了 1 bit
- 同样的方法计算,发送 34 个字多了 2 bit,... 发送 39 个字剩余 7 bit,发送 40 个字正好 35 Byte,没有多余的 bit...
- 根据协议,多余的 bit 需要置零,除非是多出来 7 bit,7 个 0 会和 GSM-7 的
@
字符冲突,这时候应该置为0001101
,也就是 GSM-7 中的\r
回车字符。
- 如果长于 160 个字符,也是需要切割,除去 UDH 的 6 Byte = 6 * 8 bit = 48 bit,还剩 1120 bit - 48 bit = 1072 bit,
最后:
- 关于 GSM-7 的详细信息,可以参考:2022/01/05,GSM-7 编码。
- 关于 UDH 的详细信息,可以参考:2022/05/13,CMPP: UDHI 头。
- https://en.wikipedia.org/wiki/Concatenated_SMS
补充:
- 部分通道采用 7 Byte 的 UDH (短信批次标识由 1 Byte 改成 2 Byte),所以短信切割长度是 152 个字符((140 - 7) * 8 / 7)。
- 如果短信采用 GSM-7 编码,UDH 需要按 7 bit 对齐,也就是说如果是 6B 的 UDH,最后需要占用 49 bit,UDH 后面的 1 bit 填 0。