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

SMS中用Unicode编码发送中文

[复制链接]

该用户从未签到

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

EDA365欢迎您登录!

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

x
SMS中用Unicode编码发送中文
9 D* j  o  t- }0 U: t% N9 [; F

7 M, ~$ W+ q: D# ]作者: 陈轶飞 7 o( G2 B  m! _* i
2 I  x: h5 E1 v9 O( ]
关键词: SMS、PDU、Unicode、GB2312、linux、编码转换   r. ?! k4 [; _5 f
) ?/ b5 }+ p9 I7 I
SMS是由Esti 所制定的一个规范(GSM 03.40 和 GSM 03.38)。有两种方式来发送和接收SMS消息:文本模式或者PDU(protocol description unit)模式。文本模式只能发送普通的ASCII字符,而要发送图片、铃声、其它编码的字符(如中文)就必须采用PDU模式。
. S9 ^1 l8 T, m- O8 WPDU模式中,可以采用三种编码方式来编码要发送的内容,分别是 7-bit编码、8-bit编码、16-bit编码。7-bit编码用于发送普通的ASCII字符;8-bit编码通常用于发送数据消息,比如图片和铃声等;而16-bit编码用于发送Unicode字符。在这三种编码方式下,可以发送的较大字符数分别是 160、 140、 70。
0 K! R1 @" z' I# L若要发送中文(或日文等),必须采用PDU模式的Unicode编码方式。
' u+ q& ]4 n, A, l8 F* t我最近参与了一个在linux下收发短信的项目。其中,需要实现中文的发送和接收。由于原来没有中文编码、Unicode编码的经验,所以查了一些资料,也在一些论坛上提了一些问题。现在把它整理出来,希望对以后再做类似项目的朋友有个帮助。我写的比较简单,关于PDU的规范,可以看这里:http://www.ascend-tech.com.cn/sustain/SMS_PDU-mode.pdf ,或者去wavecom的网站上找找看。 % ?+ v0 X1 h3 G

+ g, b% S) |6 s7 M/ _1、 GB2312 编码到Unicode 编码的转换
" i1 s  z: D0 [3 ?! v
6 j$ A  w" P& P. E' Y4 d在 Redhat 7.3系统上,默认是用GB2312编码保存中文字符的(对于中英文混合的文本也是如此)。所以首先需要把 GB2312 编码的字符串转换到 Unicode编码的字符串。GB2312编码是一种多字节编码方式,对于中文,用2个字节表示,对于英文,用1个字节表示,就是英文的ascii码。(注:我没有仔细看过GB2312编码的规范,以上理解是实际开发中得出来的,不能保证正确性)。Unicode编码是双字节编码方式,对所有字符,都采用2个字节编码。在linux平台上,GB2312编码到Unicode编码的转换,可以有三种实现方式(或者更多): , d8 I" F; R' O, t9 o* A4 C
1)、用 mbstowcs () 函数。就是多字节编码到宽字符的转换。我试过它,可以正确的转换,但是这个函数可能不是很可靠。
% k# {3 o9 Q3 S( c; ?' K8 v$ N# B2 |. s: ]
2)、用 GB2312 à Unicode 的转换表,手动查表转换。网上有这样的转换表,你需要对每一个GB2312字符,根据它是中文字符还是英文字符,分别转换。
& }' T7 X; {) i" a% k0 s7 `5 Z. `# ^$ _0 t8 l! K- O
3)、用 iconv () 函数。这可能是linux上的标准的方法,不仅可以转换GB2312到Unicode,还可以在任意的两种编码之间转换(前提是linux系统要支持这些编码)。
% d5 |0 u: ?2 |7 s& U6 b首先要用 iconv_open(), 打开一个转换句柄,指定两种转换前的编码和转换后的编码。
. d9 O( d/ a6 X3 C$ g' t- K+ r然后用 icnov() 作转换。较后用 iconv_close()关闭句柄,释放资源。
8 ]+ y9 H$ P) R0 ]" U1 A
: X* R: {/ u, u# e8 q, H/ j0 l# G& y+ `4 C0 ?. g0 ^9 g* q

6 X# D8 ]9 S' l#include <iconv.h> $ U4 l: N3 R: l9 M4 ?) h
( H+ r, g0 u+ v5 G9 f: |8 o
#define BUFLEN 200
6 J6 y) B! X% z% c  _char inbuf[BUFLEN];
( P6 z1 Y" U' P" {char outbuf[BUFLEN]; ) V  R% {; G2 ^9 h
char* pin = inbuf; ) Q. |3 ^9 F1 S2 P
char* pout = outbuf; , |3 z& l5 I2 f& o2 d  n1 d
) c/ D0 H( Q) I3 X
…打开文件,读入GB2312数据到inbuf,数据长度为 len
8 A& i1 L! ]; n( L
4 x2 U; H9 d9 |int inleft = len;
- C/ ]" i  M0 K3 E0 }int outleft = BUFLEN;
1 w& p+ F7 p* k
; @: B6 T; w8 l" g; Aiconv_t cd;
5 C& a6 f9 q  F8 _. G; mif((cd = iconv_open(“gb2312”, “unicode”)) == (iconv_t)-1) : v' V2 g7 u$ }9 L' c  @: |9 q
return –1; " z' q2 u1 L; P5 g8 n
if(iconv(cd, &pin, &inleft, &pout, &outleft) == (size_t)-1)
5 d) n9 B' c' l' |- i$ w4 Jreturn –1;
# D5 j' d6 a2 ]9 oiconv_close(cd);
+ `1 P5 P5 I8 M6 E# N! q; e& s" |% W& h9 z
使用 iconv () 时,需要注意参数的使用,inleft 是输入缓冲区数据数据长度,outleft是输出缓冲区大小。(需要保证输出缓冲区足够大)。
, J/ E3 A. p! r# y( d: n转换以后,outleft 是outbuf中空闲空间的大小,所以 BUFLEN-outleft 才是真正的Unicode数据长度。 6 x0 o, }7 o5 q
注意:不论是GB2312编码,还是Unicode编码,在内存中都是一些字节序列,所以我们可以统一用 类型为 char(或者unsigned char)的字符数组来保存。所以,BUFLEN-outleft 是 字符(char)个数,而不是Unicode字符个数。
9 @& X$ O/ K2 P6 ]! V; U& V6 t; ]% E' E! D' S, a+ ^1 E" d
; M# q( @: M6 s
2、 Unicode 编码到 16-bit 编码的转换 1 ^, V* a2 Z8 ?6 w' a
6 u" k5 n3 `6 x+ D6 |$ D# r
在得到 Unicode编码以后,还需要转换到 PDU 的16-bit 编码,才可以正确的发送。在这个转换过程中,需要注意两点:
( l$ r0 g0 K/ _4 s9 H5 u0 f1)、Unicode 编码最开始的 0xFEFF标志要被去除,在0xFEFF之后的内容,才是真正的Unicode字符。(至于为什么有这个0xfeff标志,知道的朋友告诉我一声,呵呵)。 9 K- V' X# ~4 n3 g' p% l- b
& b6 m5 a  k! [  r
2)、Unicode 是双字节字符,由于我的系统是小端字节序(little-endian),也就是说,在存储的时候,是先低位,后高位,例如“中”的Unicode编码是 0x4E2D,存储的时候是 2D4E,在转换到 16-bit编码的时候,要注意这个顺序的不同。当然,如果你的系统是大端字节序(big-endian),那么就不用这样做了。
, A, h7 g* A4 Q7 }9 J
# v4 g- X, E, pOK,关于如何将 0x4E2D 的Unicode编码转换到 “4E2D” 的16-bit编码,我就不多写了。
* f- \# J) ~: i  o, E
3 o: D  l- o% X1 {$ W! g# |  k0 t+ v! ~& i3 q: A" C7 a( Y- `
3、正确计算16-bit 编码的消息体长度 / x) S- z9 @  {$ r3 P: ~9 ?- j

# n; W; w! q% E4、正确设置 First-Octet 、TP-MR、TP-PID、TP-DCS、TP-VP
/ e8 O* g- m! M6 U1 ~* }2 K& J; j
1 _& Y6 V* ]$ M+ l; G# e7 p在PDU格式中,First-Octet 、TP-MR、TP-PID、TP-DCS、TP-VP的设置正确与否,对能否发送 Unicode 至关重要。根据协议规范以及我的调试结果,以上几个标志的正确设置分别为(都是16进制): 7 y* [: q% v! C7 w- |+ a0 s
First-Octet : 11 ' \2 L1 K2 V' e6 K& Y
TP-MR : 00
7 H# [( r; o( O2 L5 TTP-PID : 00 ' f6 @1 r# f+ e
TP-DCS : 08 (编码方式,16-bit)
& ]: L7 z, Y  \! V6 M8 l# FTP-VP : A7
5 D6 @' P8 S. x! S) t7 F6 \" ]: q) u9 q, ~( K: g+ M( K
经过以上步骤,已经可以做到发送中文字符了。 % M1 w6 s; ?2 \- Y
希望这篇文档,能为准备在linux下做短信开发的朋友提供一些帮助。 4 c/ |' t+ U" A4 T- |  `/ n% c

% k; Q2 T% Q& t8 D+ B% O/ J
# @3 h! ?) S* k# R3 T( c参考文献: ( _( e2 a+ i0 E; e3 @
★ An introduction to the SMS in PDU mode GSM Recommendation phase 2. X& c: H$ R. g0 R8 k- `0 w- n% K

该用户从未签到

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

本版积分规则

关闭

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

EDA365公众号

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

GMT+8, 2025-9-6 15:49 , Processed in 0.125000 second(s), 23 queries , Gzip On.

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

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

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