TOC

短信长度到底是怎么规定的

短信的通信协议从 2G 时代一直到现在基本没有什么变化。

  1. 支持 140 个字节(140 Byte = 140 * 8 bit = 1120 bit)
  2. 支持 GSM-7 编码,8bit 编码,UCS-2 编码
  3. GSM-7 每个字符 7 bit,支持英语和西欧语言,配合 National Language Shift Table 功能,能够支持一些其他字母文字的语言。
  4. UCS-2 每个字符 2 Byte(16 bit),传递一些 GSM-7 框架不支持的语言,比如中文(字符太多,7bit 方案反倒不合适)。
  5. 8bit 用来传递图片等二进制数据。
  6. 根据短信协议,如果长度超出范围,需要在短信前面加上一个二进制头部,叫做 UDH(User Data Header)。
  7. UDH 一共 6 个字节
  8. 包含一些 SMS 拓展字段
  9. 对于短信拆分来讲,里面有这一批短信的总条数,和当前这条短信的序号

所以,

  1. 如果是中文短信,用 UCS-2 编码,每个字符 2 Byte,一条短信最长支持 70 个中文字符(140 Byte / 2)。
  2. 注意:所有字符,包括 ASCII 中的英文、数字、半角的标点,全部需要转换成 UCS-2 的 2 Byte 编码。
  3. 如果长于 70 个字符,就需要切割成多条,UDH 头部需要 6 Byte,每条短信还剩 134 Byte,除以二,还能装 67 个字符。
  4. 例如:140 个中文字符的短信,需要切割成 67 + 67 + 6 三条短信。
  5. 如果是英文短信,或者部分西欧语言,可以使用 GSM-7 编码,每个字符 7 bit,一条短信最长支持 160 个字符(1120 bit / 7)。
  6. 如果长于 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,不参与计费)。
  7. 例如,320 个英文字符,需要切割成 153 + 153 + 14 三条短信。
  8. 注意:GSM-7 编码中,9 个拓展字符 ^ ~ \ | { } [ ] € 需要算两个字符。非常重要
  9. 数据通信中都是使用 Byte 为单位,用 GSM-7 编码可能会除不尽,也就是说剩余 1 ~ 7 bit。比如:
    1. 发送 33 个字,33 * 7 bit = 231 bit,需要 29 Byte (232 bit) 来装,就多了 1 bit
    2. 同样的方法计算,发送 34 个字多了 2 bit,... 发送 39 个字剩余 7 bit,发送 40 个字正好 35 Byte,没有多余的 bit...
    3. 根据协议,多余的 bit 需要置零,除非是多出来 7 bit,7 个 0 会和 GSM-7 的 @ 字符冲突,这时候应该置为 0001101,也就是 GSM-7 中的 \r 回车字符。

最后:

  1. 关于 GSM-7 的详细信息,可以参考:2022/01/05,GSM-7 编码
  2. 关于 UDH 的详细信息,可以参考:2022/05/13,CMPP: UDHI 头
  3. https://en.wikipedia.org/wiki/Concatenated_SMS

补充:

  1. 部分通道采用 7 Byte 的 UDH (短信批次标识由 1 Byte 改成 2 Byte),所以短信切割长度是 152 个字符((140 - 7) * 8 / 7)。
  2. 如果短信采用 GSM-7 编码,UDH 需要按 7 bit 对齐,也就是说如果是 6B 的 UDH,最后需要占用 49 bit,UDH 后面的 1 bit 填 0。