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

SMS中用Unicode编码发送中文

[复制链接]

该用户从未签到

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

EDA365欢迎您登录!

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

x
SMS中用Unicode编码发送中文

, j% G" ]' I0 H  f; [+ x5 d: l  T6 O$ G
作者: 陈轶飞 1 Q# C) J9 o. E

% D. y4 A7 L- z" W8 ?. ^( \关键词: SMS、PDU、Unicode、GB2312、linux、编码转换
" @6 _/ K$ Y! ~! A7 o* s: \4 u0 E7 g+ j/ N. H2 h) J9 w
SMS是由Esti 所制定的一个规范(GSM 03.40 和 GSM 03.38)。有两种方式来发送和接收SMS消息:文本模式或者PDU(protocol description unit)模式。文本模式只能发送普通的ASCII字符,而要发送图片、铃声、其它编码的字符(如中文)就必须采用PDU模式。
* K( q: _4 z1 X, O( v! a1 nPDU模式中,可以采用三种编码方式来编码要发送的内容,分别是 7-bit编码、8-bit编码、16-bit编码。7-bit编码用于发送普通的ASCII字符;8-bit编码通常用于发送数据消息,比如图片和铃声等;而16-bit编码用于发送Unicode字符。在这三种编码方式下,可以发送的较大字符数分别是 160、 140、 70。 , N! B7 G) c+ j7 [% Z* U. j
若要发送中文(或日文等),必须采用PDU模式的Unicode编码方式。
) q6 E; B6 A  a$ [3 W5 U我最近参与了一个在linux下收发短信的项目。其中,需要实现中文的发送和接收。由于原来没有中文编码、Unicode编码的经验,所以查了一些资料,也在一些论坛上提了一些问题。现在把它整理出来,希望对以后再做类似项目的朋友有个帮助。我写的比较简单,关于PDU的规范,可以看这里:http://www.ascend-tech.com.cn/sustain/SMS_PDU-mode.pdf ,或者去wavecom的网站上找找看。 : k) f$ n6 R, \8 c5 h
/ h$ R& Y2 W8 k4 y
1、 GB2312 编码到Unicode 编码的转换 ( [3 d- P5 z' ]

" y6 _% J" E1 J/ }# y7 C$ g在 Redhat 7.3系统上,默认是用GB2312编码保存中文字符的(对于中英文混合的文本也是如此)。所以首先需要把 GB2312 编码的字符串转换到 Unicode编码的字符串。GB2312编码是一种多字节编码方式,对于中文,用2个字节表示,对于英文,用1个字节表示,就是英文的ascii码。(注:我没有仔细看过GB2312编码的规范,以上理解是实际开发中得出来的,不能保证正确性)。Unicode编码是双字节编码方式,对所有字符,都采用2个字节编码。在linux平台上,GB2312编码到Unicode编码的转换,可以有三种实现方式(或者更多):
! j$ ~' r0 A  X" c1)、用 mbstowcs () 函数。就是多字节编码到宽字符的转换。我试过它,可以正确的转换,但是这个函数可能不是很可靠。
" U* T4 J' a0 ?: d2 k; C' z
0 k4 R" A- h' _1 ?4 Q7 {2 j2)、用 GB2312 à Unicode 的转换表,手动查表转换。网上有这样的转换表,你需要对每一个GB2312字符,根据它是中文字符还是英文字符,分别转换。
$ F" D% @$ S, R4 n2 \. r) F
. d, T- Q! S# U9 ]( E3)、用 iconv () 函数。这可能是linux上的标准的方法,不仅可以转换GB2312到Unicode,还可以在任意的两种编码之间转换(前提是linux系统要支持这些编码)。 - S/ U/ l5 G) K
首先要用 iconv_open(), 打开一个转换句柄,指定两种转换前的编码和转换后的编码。
' w8 Y" X2 u# J8 J* q6 p! f然后用 icnov() 作转换。较后用 iconv_close()关闭句柄,释放资源。
9 i. e$ @  \# g0 k; C  N( T
. X: B0 P1 y( o6 }: L2 ^0 R- _( H) ]. x
7 }  B0 N: t+ Y! M- ?, O0 n% `9 v
#include <iconv.h>
  m: y$ x3 |9 Z' g* S. C4 u
; P5 T& A4 c. E0 h#define BUFLEN 200 9 \" l+ R$ ?2 C- V
char inbuf[BUFLEN]; # M, p* V9 v7 t7 W1 |2 q
char outbuf[BUFLEN];
: p$ e3 s% [" r! z; g- A4 h+ u* cchar* pin = inbuf;
$ n6 z" g/ d# V: B3 g- y" T! Q: ?char* pout = outbuf;
( ~  `* F! [6 U+ A9 r2 G$ R
7 i7 j& k# U) N- V8 w2 I/ r…打开文件,读入GB2312数据到inbuf,数据长度为 len   h# N/ s7 |- _

- i  \1 I. z0 c- ]! A' F9 Bint inleft = len;
8 y# W3 f2 \9 n% c& M3 Mint outleft = BUFLEN;
( m$ S& C% S$ k; H; F& j9 g5 _* ?# F3 B- e# }6 K5 S; {
iconv_t cd; & h1 D' c# I5 b( g% n
if((cd = iconv_open(“gb2312”, “unicode”)) == (iconv_t)-1) 8 R& z- a4 k( u  x4 j+ d8 ~
return –1; 6 N7 a3 {' q! s  ^
if(iconv(cd, &pin, &inleft, &pout, &outleft) == (size_t)-1) - J* ?! C+ _3 T- w
return –1;
  _, P- k; R& M& t, kiconv_close(cd); + A: ~1 i( m- n7 _0 Z" t! Z

' S9 T+ V% [, M使用 iconv () 时,需要注意参数的使用,inleft 是输入缓冲区数据数据长度,outleft是输出缓冲区大小。(需要保证输出缓冲区足够大)。 2 ~' h/ S! Y) h& n/ n8 x# \) b
转换以后,outleft 是outbuf中空闲空间的大小,所以 BUFLEN-outleft 才是真正的Unicode数据长度。 , b2 u+ Q3 X# [
注意:不论是GB2312编码,还是Unicode编码,在内存中都是一些字节序列,所以我们可以统一用 类型为 char(或者unsigned char)的字符数组来保存。所以,BUFLEN-outleft 是 字符(char)个数,而不是Unicode字符个数。 9 N! r' F' {3 ^' {

7 K& J$ c. Y' q, V
, i( }7 r, j" r# A6 o6 z* {1 o2、 Unicode 编码到 16-bit 编码的转换 ! G3 `/ \& g4 n3 g  R

- J- Z, a+ V( u; a) D1 _& S: E在得到 Unicode编码以后,还需要转换到 PDU 的16-bit 编码,才可以正确的发送。在这个转换过程中,需要注意两点:
3 [3 [) A! A5 H  E3 v1)、Unicode 编码最开始的 0xFEFF标志要被去除,在0xFEFF之后的内容,才是真正的Unicode字符。(至于为什么有这个0xfeff标志,知道的朋友告诉我一声,呵呵)。 * s4 D5 ^# u7 d- D8 B! s* G; v( k* R* o
1 K. f) G. u9 [# }
2)、Unicode 是双字节字符,由于我的系统是小端字节序(little-endian),也就是说,在存储的时候,是先低位,后高位,例如“中”的Unicode编码是 0x4E2D,存储的时候是 2D4E,在转换到 16-bit编码的时候,要注意这个顺序的不同。当然,如果你的系统是大端字节序(big-endian),那么就不用这样做了。
+ ^; d: V5 s0 M- e7 v2 o& I' O5 x' Y3 i' U: W4 E2 ]+ Y0 G% `
OK,关于如何将 0x4E2D 的Unicode编码转换到 “4E2D” 的16-bit编码,我就不多写了。
% V1 X# E+ I+ R' u, n
5 g, g7 m9 w* r7 h1 w8 w. \* p  ?/ y- @6 G) g
3、正确计算16-bit 编码的消息体长度 4 A# P; `1 w1 z+ X

7 Y" e/ _+ u# C9 J4、正确设置 First-Octet 、TP-MR、TP-PID、TP-DCS、TP-VP
! e/ S: ?, K5 s. x/ j* l" Q( N  ~' |% H1 |) g7 W* Z0 }* {( p% |
在PDU格式中,First-Octet 、TP-MR、TP-PID、TP-DCS、TP-VP的设置正确与否,对能否发送 Unicode 至关重要。根据协议规范以及我的调试结果,以上几个标志的正确设置分别为(都是16进制):
0 Y- V! o) _4 D) I9 q  cFirst-Octet : 11 3 F& e' S* P3 j! x! s: M
TP-MR : 00 4 G9 K3 z$ y; ?' \9 k! Q
TP-PID : 00 5 C: q5 G, R, ]  L. \
TP-DCS : 08 (编码方式,16-bit)
. r( \9 @- X3 V+ K  b9 FTP-VP : A7
" ]' k' }) P1 ^4 x* ^' {
( p  q# I' v  l# r$ Q+ l! g经过以上步骤,已经可以做到发送中文字符了。
. Y1 l$ C7 R7 F$ z希望这篇文档,能为准备在linux下做短信开发的朋友提供一些帮助。 * |/ k; `5 D  ~" P. r3 x) k

2 w+ F+ i5 ^, c3 T
7 m3 ~; i0 g6 Y. ~$ p/ J参考文献: " b$ y: _" @7 F9 J
★ An introduction to the SMS in PDU mode GSM Recommendation phase 2
4 Y8 ^. G# \7 ~( X6 z

该用户从未签到

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

本版积分规则

关闭

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

EDA365公众号

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

GMT+8, 2025-6-6 04:21 , Processed in 0.078125 second(s), 23 queries , Gzip On.

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

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

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