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

SMS中用Unicode编码发送中文

[复制链接]

该用户从未签到

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

EDA365欢迎您登录!

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

x
SMS中用Unicode编码发送中文
% ]- M2 }' ?/ x  |0 U2 Q9 T

& b0 l  V% y  _作者: 陈轶飞
5 T* ^; X/ G' M! ]; ?3 o' t* h. E4 U' E4 o. O# _3 c" p" h& Z
关键词: SMS、PDU、Unicode、GB2312、linux、编码转换
7 L3 }, T! \4 G. x1 E0 j4 A0 R- Z: P& K- p( e1 n, z# C! p
SMS是由Esti 所制定的一个规范(GSM 03.40 和 GSM 03.38)。有两种方式来发送和接收SMS消息:文本模式或者PDU(protocol description unit)模式。文本模式只能发送普通的ASCII字符,而要发送图片、铃声、其它编码的字符(如中文)就必须采用PDU模式。
$ F. D0 \6 K% k& j" C! N9 |PDU模式中,可以采用三种编码方式来编码要发送的内容,分别是 7-bit编码、8-bit编码、16-bit编码。7-bit编码用于发送普通的ASCII字符;8-bit编码通常用于发送数据消息,比如图片和铃声等;而16-bit编码用于发送Unicode字符。在这三种编码方式下,可以发送的较大字符数分别是 160、 140、 70。
' n- K/ U; K/ }* q若要发送中文(或日文等),必须采用PDU模式的Unicode编码方式。 - L: U5 E; W1 I$ t
我最近参与了一个在linux下收发短信的项目。其中,需要实现中文的发送和接收。由于原来没有中文编码、Unicode编码的经验,所以查了一些资料,也在一些论坛上提了一些问题。现在把它整理出来,希望对以后再做类似项目的朋友有个帮助。我写的比较简单,关于PDU的规范,可以看这里:http://www.ascend-tech.com.cn/sustain/SMS_PDU-mode.pdf ,或者去wavecom的网站上找找看。 7 O& ~, U- {. _2 ]" l% P1 k: E1 ]
& M: D! D" F# Q
1、 GB2312 编码到Unicode 编码的转换
) a5 G6 U3 d# M& E
" V: v# J. M2 O* m在 Redhat 7.3系统上,默认是用GB2312编码保存中文字符的(对于中英文混合的文本也是如此)。所以首先需要把 GB2312 编码的字符串转换到 Unicode编码的字符串。GB2312编码是一种多字节编码方式,对于中文,用2个字节表示,对于英文,用1个字节表示,就是英文的ascii码。(注:我没有仔细看过GB2312编码的规范,以上理解是实际开发中得出来的,不能保证正确性)。Unicode编码是双字节编码方式,对所有字符,都采用2个字节编码。在linux平台上,GB2312编码到Unicode编码的转换,可以有三种实现方式(或者更多):   r: }' y5 [. \9 M  @
1)、用 mbstowcs () 函数。就是多字节编码到宽字符的转换。我试过它,可以正确的转换,但是这个函数可能不是很可靠。 2 Y8 S) v. ?/ _
/ F# s" z1 g9 z6 o
2)、用 GB2312 à Unicode 的转换表,手动查表转换。网上有这样的转换表,你需要对每一个GB2312字符,根据它是中文字符还是英文字符,分别转换。 7 C+ H. W  T2 S7 ~

: o5 n6 f6 u# ~5 ~7 Q3)、用 iconv () 函数。这可能是linux上的标准的方法,不仅可以转换GB2312到Unicode,还可以在任意的两种编码之间转换(前提是linux系统要支持这些编码)。 5 F: s( Q) l1 E2 I, H' a
首先要用 iconv_open(), 打开一个转换句柄,指定两种转换前的编码和转换后的编码。
* _+ q2 t, S8 N- T$ w然后用 icnov() 作转换。较后用 iconv_close()关闭句柄,释放资源。 % X" W' o: `- b$ g) }+ ?9 d

$ A; z' [' |4 \4 ?4 f$ {
, {5 @  N7 F+ v1 x( v4 H. v, H+ x) E9 o1 s; s) w
#include <iconv.h>
6 Y. C4 W. o5 @  t7 \4 B" M  Z% f
#define BUFLEN 200
1 I" B, e: {0 ~* S& N" m4 f2 Ichar inbuf[BUFLEN];   I8 K3 \2 d. Q! z/ I7 [# b9 j
char outbuf[BUFLEN]; - U/ }; ?; f# }& t( M3 t, E9 n
char* pin = inbuf; 8 k* w4 Z" v! q- y- ^- l
char* pout = outbuf;
1 C/ V6 O# a( k: i- E* y- j  b8 n' ?5 n- A( h! b+ Y
…打开文件,读入GB2312数据到inbuf,数据长度为 len
, t6 u  Y6 x9 R4 A2 [8 n/ h& w8 p) u" F7 a1 l* }& n0 @- |* S
int inleft = len; 8 x, J% Q3 b3 z2 b+ T" C
int outleft = BUFLEN;
% L( V' D( f8 @. g" {, A( v6 L$ c+ _; l, J
iconv_t cd; , k( i. Q; S( k; H2 _! m, y
if((cd = iconv_open(“gb2312”, “unicode”)) == (iconv_t)-1) $ p+ ]9 v- o1 J8 y8 G
return –1;   [% O; P0 j& w1 g
if(iconv(cd, &pin, &inleft, &pout, &outleft) == (size_t)-1)
7 W/ O( e0 i+ C* U) N+ B* areturn –1;
; M3 u" v" N' ]( h' D' ?% wiconv_close(cd);
6 E& I3 g6 T! ?0 D& i! F3 U2 @; g+ C7 K6 z- e
使用 iconv () 时,需要注意参数的使用,inleft 是输入缓冲区数据数据长度,outleft是输出缓冲区大小。(需要保证输出缓冲区足够大)。
: a2 u* g. \2 E; c7 E# ~转换以后,outleft 是outbuf中空闲空间的大小,所以 BUFLEN-outleft 才是真正的Unicode数据长度。
# p$ ]+ G8 x  q& p注意:不论是GB2312编码,还是Unicode编码,在内存中都是一些字节序列,所以我们可以统一用 类型为 char(或者unsigned char)的字符数组来保存。所以,BUFLEN-outleft 是 字符(char)个数,而不是Unicode字符个数。 / Y5 f$ p! H$ z, S, p) \8 z

" b- [  e; p4 p; F& I* q5 I$ k. Z& r( I* P) l5 q; w2 V
2、 Unicode 编码到 16-bit 编码的转换
1 ]4 M6 C8 K4 A6 z" B
3 R$ C+ K5 P6 y/ Y在得到 Unicode编码以后,还需要转换到 PDU 的16-bit 编码,才可以正确的发送。在这个转换过程中,需要注意两点:
! f9 V9 o7 b9 J3 }- A( }1)、Unicode 编码最开始的 0xFEFF标志要被去除,在0xFEFF之后的内容,才是真正的Unicode字符。(至于为什么有这个0xfeff标志,知道的朋友告诉我一声,呵呵)。 8 y0 S( y# R8 m. z8 r0 D

* y* ?- {% c8 p$ I/ C( T& k2)、Unicode 是双字节字符,由于我的系统是小端字节序(little-endian),也就是说,在存储的时候,是先低位,后高位,例如“中”的Unicode编码是 0x4E2D,存储的时候是 2D4E,在转换到 16-bit编码的时候,要注意这个顺序的不同。当然,如果你的系统是大端字节序(big-endian),那么就不用这样做了。   S, _( b3 w, a4 D, J0 q. Y

9 z$ m) B  A& U' I, K6 M0 |% f0 NOK,关于如何将 0x4E2D 的Unicode编码转换到 “4E2D” 的16-bit编码,我就不多写了。 ( }/ h) @: w7 u1 r) k
' k5 P3 M" Y0 n9 k

) u7 W* N% k9 z# w% E, g3、正确计算16-bit 编码的消息体长度 " X( [% y& F! D% x
7 _4 |. i1 [4 ?  F' ^4 v2 d% H
4、正确设置 First-Octet 、TP-MR、TP-PID、TP-DCS、TP-VP ; Z# r7 h2 `1 i8 a( A. `8 j

8 l- A( S6 j; _在PDU格式中,First-Octet 、TP-MR、TP-PID、TP-DCS、TP-VP的设置正确与否,对能否发送 Unicode 至关重要。根据协议规范以及我的调试结果,以上几个标志的正确设置分别为(都是16进制): " R. _. W  t8 d6 O% h3 j; S" g
First-Octet : 11
& `7 M2 ?9 ^& A+ e! s3 p( S. tTP-MR : 00 # E4 O* G# U+ T# V# h/ E
TP-PID : 00 - g8 f# W+ T$ u9 [
TP-DCS : 08 (编码方式,16-bit)
: u6 q$ R+ k, w3 g# w5 i$ M; hTP-VP : A7
. M/ [# V& `' [" x# p8 O: D) B! k* I5 d( b8 u6 o0 [
经过以上步骤,已经可以做到发送中文字符了。
) X! E* j4 X$ a  @* R% K! s希望这篇文档,能为准备在linux下做短信开发的朋友提供一些帮助。
3 E' C+ t* j$ w* |. H* P- Q9 b6 W% c4 m8 B+ `0 M1 ~

& x. v: ]$ d. n参考文献:
+ ]) ~* i9 C5 E& n( L★ An introduction to the SMS in PDU mode GSM Recommendation phase 2
8 v5 F9 a- U6 _! g; H  b

该用户从未签到

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

本版积分规则

关闭

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

EDA365公众号

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

GMT+8, 2025-7-19 13:23 , Processed in 0.109375 second(s), 23 queries , Gzip On.

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

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

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