找回密码
 注册
关于网站域名变更的通知
查看: 430|回复: 2
打印 上一主题 下一主题

SMS中用Unicode编码发送中文

[复制链接]

该用户从未签到

跳转到指定楼层
1#
发表于 2019-7-5 07:00 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

EDA365欢迎您登录!

您需要 登录 才可以下载或查看,没有帐号?注册

x
SMS中用Unicode编码发送中文
& V& ^6 ^& H4 \4 v$ G$ }  x/ Z5 d
# c/ c# A- C! V
作者: 陈轶飞 9 ^- m2 n( T% |1 I, z! V' B* L
5 f' R! _  b3 \, U+ ~8 Y
关键词: SMS、PDU、Unicode、GB2312、linux、编码转换 / v7 D6 U" G' ]: \
3 {! x( P  v3 t4 a7 B
SMS是由Esti 所制定的一个规范(GSM 03.40 和 GSM 03.38)。有两种方式来发送和接收SMS消息:文本模式或者PDU(protocol description unit)模式。文本模式只能发送普通的ASCII字符,而要发送图片、铃声、其它编码的字符(如中文)就必须采用PDU模式。
* P& b+ z) J9 iPDU模式中,可以采用三种编码方式来编码要发送的内容,分别是 7-bit编码、8-bit编码、16-bit编码。7-bit编码用于发送普通的ASCII字符;8-bit编码通常用于发送数据消息,比如图片和铃声等;而16-bit编码用于发送Unicode字符。在这三种编码方式下,可以发送的较大字符数分别是 160、 140、 70。 # r' [: o3 U1 Z( F" _. p" H
若要发送中文(或日文等),必须采用PDU模式的Unicode编码方式。
6 d, o4 @, y) `* [- ^我最近参与了一个在linux下收发短信的项目。其中,需要实现中文的发送和接收。由于原来没有中文编码、Unicode编码的经验,所以查了一些资料,也在一些论坛上提了一些问题。现在把它整理出来,希望对以后再做类似项目的朋友有个帮助。我写的比较简单,关于PDU的规范,可以看这里:http://www.ascend-tech.com.cn/sustain/SMS_PDU-mode.pdf ,或者去wavecom的网站上找找看。 5 [# n6 Z' i: C: u" ]

5 ?& P( w. W; z( O& y) r9 [6 a9 Y1、 GB2312 编码到Unicode 编码的转换
$ w5 d' Q4 e9 {9 y' s
: k. S; a( C2 y7 g" l3 q; s在 Redhat 7.3系统上,默认是用GB2312编码保存中文字符的(对于中英文混合的文本也是如此)。所以首先需要把 GB2312 编码的字符串转换到 Unicode编码的字符串。GB2312编码是一种多字节编码方式,对于中文,用2个字节表示,对于英文,用1个字节表示,就是英文的ascii码。(注:我没有仔细看过GB2312编码的规范,以上理解是实际开发中得出来的,不能保证正确性)。Unicode编码是双字节编码方式,对所有字符,都采用2个字节编码。在linux平台上,GB2312编码到Unicode编码的转换,可以有三种实现方式(或者更多): / Z  c3 O" d/ O" p6 w
1)、用 mbstowcs () 函数。就是多字节编码到宽字符的转换。我试过它,可以正确的转换,但是这个函数可能不是很可靠。 . z2 m3 |# b# w) e

" C% [. O. Y: [+ e2)、用 GB2312 à Unicode 的转换表,手动查表转换。网上有这样的转换表,你需要对每一个GB2312字符,根据它是中文字符还是英文字符,分别转换。
: D! l9 |2 e% v- p; u5 I% f
0 d% Z6 F" ?7 Y! ]# E3)、用 iconv () 函数。这可能是linux上的标准的方法,不仅可以转换GB2312到Unicode,还可以在任意的两种编码之间转换(前提是linux系统要支持这些编码)。
- M% c; R: _& ~首先要用 iconv_open(), 打开一个转换句柄,指定两种转换前的编码和转换后的编码。 " S9 `2 o& S/ F$ g/ B5 ^
然后用 icnov() 作转换。较后用 iconv_close()关闭句柄,释放资源。
( j  N: |7 W. P7 r# a; O/ S+ n+ r

- P! D0 g1 a2 i0 u6 A( W% ~2 R# g! k, L; Y
#include <iconv.h>
5 m9 h; V. U7 U# P% r+ d5 ~
# H+ ?; ]7 a7 a! V$ z#define BUFLEN 200 % u2 T* Q* }* w. R4 o5 f- o2 c* W
char inbuf[BUFLEN]; ! v! O. r3 `2 J5 Y9 o
char outbuf[BUFLEN]; % `0 u9 ~8 f2 T! I
char* pin = inbuf; ; j6 N6 i; h4 }/ T) @& `
char* pout = outbuf; , D$ L" U( }3 l7 s$ Z* R
2 `; v" p% v' {% y6 ~1 l2 n3 S, U
…打开文件,读入GB2312数据到inbuf,数据长度为 len 6 }3 F! a; @; N( R) g3 u5 \

- E7 P/ O. }& P! Vint inleft = len; 8 e! G; P& J1 A0 o4 q; w5 C3 J' O
int outleft = BUFLEN; 7 [6 ]2 V! B" s. M
* B8 o) S  v' s- g3 A0 J) C! y
iconv_t cd;
- @2 k- d6 F; r) _) r+ o8 g% xif((cd = iconv_open(“gb2312”, “unicode”)) == (iconv_t)-1)
% V1 P, s' j  o. `9 K; Creturn –1;
1 @! @+ _( ?8 r( X7 s1 D' `if(iconv(cd, &pin, &inleft, &pout, &outleft) == (size_t)-1)
& p$ {* G0 r1 |9 Mreturn –1; ' Q% t) s( e  h. p% X+ Y
iconv_close(cd);
4 |( ?0 t6 }4 }8 ?- V9 u2 D, t5 h1 V% r
使用 iconv () 时,需要注意参数的使用,inleft 是输入缓冲区数据数据长度,outleft是输出缓冲区大小。(需要保证输出缓冲区足够大)。
, p( B0 i" t2 x4 B, @转换以后,outleft 是outbuf中空闲空间的大小,所以 BUFLEN-outleft 才是真正的Unicode数据长度。 : q& R1 u# T$ j2 B8 F3 W2 f
注意:不论是GB2312编码,还是Unicode编码,在内存中都是一些字节序列,所以我们可以统一用 类型为 char(或者unsigned char)的字符数组来保存。所以,BUFLEN-outleft 是 字符(char)个数,而不是Unicode字符个数。
/ ^6 e: Q* a' I! {4 |! f8 d, @* k  z, g% s: z- e% ?
: u8 h3 ~- T* h3 W# V! A
2、 Unicode 编码到 16-bit 编码的转换
. k5 v* Z' D8 k0 N( D. a2 @' _0 q& O- f, B- R
在得到 Unicode编码以后,还需要转换到 PDU 的16-bit 编码,才可以正确的发送。在这个转换过程中,需要注意两点: 2 w5 g2 m, F: k0 R1 [7 p
1)、Unicode 编码最开始的 0xFEFF标志要被去除,在0xFEFF之后的内容,才是真正的Unicode字符。(至于为什么有这个0xfeff标志,知道的朋友告诉我一声,呵呵)。 / q1 T& q: H: U1 B# q

1 G% x; x1 Q- B) p, X3 U: H2)、Unicode 是双字节字符,由于我的系统是小端字节序(little-endian),也就是说,在存储的时候,是先低位,后高位,例如“中”的Unicode编码是 0x4E2D,存储的时候是 2D4E,在转换到 16-bit编码的时候,要注意这个顺序的不同。当然,如果你的系统是大端字节序(big-endian),那么就不用这样做了。
7 G$ e4 I# s8 T$ I( y
' M( r! k( f# \! I9 r  i/ n5 aOK,关于如何将 0x4E2D 的Unicode编码转换到 “4E2D” 的16-bit编码,我就不多写了。 4 I1 [: U2 S3 ?

( N/ ]6 a, A3 a+ T) m; `; ^! S" n1 U3 x9 V
3、正确计算16-bit 编码的消息体长度 & g' d% f6 y" A$ r9 O+ F
* [5 B: H# @- V1 e
4、正确设置 First-Octet 、TP-MR、TP-PID、TP-DCS、TP-VP 4 j" f& D. n% W$ \

1 M5 l( ?. ]5 I4 ^0 Y& i5 M在PDU格式中,First-Octet 、TP-MR、TP-PID、TP-DCS、TP-VP的设置正确与否,对能否发送 Unicode 至关重要。根据协议规范以及我的调试结果,以上几个标志的正确设置分别为(都是16进制):   v+ q1 C; m0 ^  Q2 D
First-Octet : 11
  h6 q4 p2 Y9 S* F( a7 QTP-MR : 00
9 x+ z0 \7 h$ E4 M7 w' p& E* FTP-PID : 00
: j, [) F& c6 ~# _  oTP-DCS : 08 (编码方式,16-bit)
5 z  [5 E4 S& v3 G3 T" zTP-VP : A7 & @3 E2 P1 r/ Q! [
6 u, K. [- W1 T' a' i' m
经过以上步骤,已经可以做到发送中文字符了。 : H* q" o8 ~* K' E0 E' s2 R
希望这篇文档,能为准备在linux下做短信开发的朋友提供一些帮助。
, V, \  y% u' q8 o7 M: T- Q1 M& J7 i8 P) Q7 ?4 n/ C

3 x/ {& @/ I$ s3 u% u5 ~; `6 O5 J参考文献:
% ^7 |1 J- ^! m+ f★ An introduction to the SMS in PDU mode GSM Recommendation phase 2  C# ^/ V- T' T' w

该用户从未签到

3#
发表于 2019-7-5 17:08 | 只看该作者
研究一下SMS中用Unicode编码发送中文 ,谢谢分享
您需要登录后才可以回帖 登录 | 注册

本版积分规则

关闭

推荐内容上一条 /1 下一条

EDA365公众号

关于我们|手机版|EDA365电子论坛网 ( 粤ICP备18020198号-1 )

GMT+8, 2025-6-7 07:09 , Processed in 0.062500 second(s), 23 queries , Gzip On.

深圳市墨知创新科技有限公司

地址:深圳市南山区科技生态园2栋A座805 电话:19926409050

快速回复 返回顶部 返回列表