LoveUnix » 编程开发 & Rational » SMS中用Unicode编码发送中文
让LU留住您的每

一天 让LU博客留住您的每一天
2005-8-26 09:37 99大话王
<!--QuoteBegin--><div class='quotetop'>QUOTE</div><div class='quotemain'><!--QuoteEBegin-->SMS中用Unicode编码发送中文<br /><br />SMS是由Esti 所制定的一个规范(GSM 03.40 和 GSM 03.38)。有两种方式来发送和接收SMS消息:文本模式或者PDU(protocol description unit)模式。文本模式只能发送普通的ASCII字符,而要发送图片、铃声、其它编码的字符(如中文)就必须采用PDU模式。 <br />PDU模式中,可以采用三种编码方式来编码要发送的内容,分别是 7-bit编码、8-bit编码、16-bit编码。7-bit编码用于发送普通的ASCII字符;8-bit编码通常用于发送数据消息,比如图片和铃声等;而16-bit编码用于发送Unicode字符。在这三种编码方式下,可以发送的最大字符数分别是 160、 140、 70。 <br />若要发送中文(或日文等),必须采用PDU模式的Unicode编码方式。 <br />我最近参与了一个在linux下收发短信的项目。其中,需要实现中文的发送和接收。由于原来没有中文编码、Unicode编码的经验,所以查了一些资料,也在一些论坛上提了一些问题。现在把它整理出来,希望对以后再做类似项目的朋友有个帮助。我写的比较简单,关于PDU的规范,可以看这里:http://www.ascend-tech.com.cn/sustain/SMS_PDU-mode.pdf&nbsp; ,或者去wavecom的网站上找找看。 <br /><br />1、 GB2312 编码到Unicode 编码的转换 <br /><br />在 Redhat 7.3系统上,默认是用GB2312编码保存中文字符的(对于中英文混合的文本也是如此)。所以首先需要把 GB2312 编码的字符串转换到 Unicode编码的字符串。GB2312编码是一种多字节编码方式,对于中文,用2个字节表示,对于英文,用1个字节表示,就是英文的ascii码。(注:我没有仔细看过GB2312编码的规范,以上理解是实际开发中得出来的,不能保证正确性)。Unicode编码是双字节编码方式,对所有字符,都采用2个字节编码。在linux平台上,GB2312编码到Unicode编码的转换,可以有三种实现方式(或者更多): <br />1)、用 mbstowcs () 函数。就是多字节编码到宽字符的转换。我试过它,可以正确的转换,但是这个函数可能不是很可靠。 <br /><br />2)、用 GB2312 à Unicode 的转换表,手动查表转换。网上有这样的转换表,你需要对每一个GB2312字符,根据它是中文字符还是英文字符,分别转换。 <br /><br />3)、用 iconv () 函数。这可能是linux上的标准的方法,不仅可以转换GB2312到Unicode,还可以在任意的两种编码之间转换(前提是linux系统要支持这些编码)。 <br />首先要用 iconv_open(), 打开一个转换句柄,指定两种转换前的编码和转换后的编码。 <br />然后用 icnov() 作转换。最后用 iconv_close()关闭句柄,释放资源。 <br /><br /><br /><br />#include &lt;iconv.h&gt; <br /><br />#define BUFLEN 200 <br />char inbuf[BUFLEN]; <br />char outbuf[BUFLEN]; <br />char* pin = inbuf; <br />char* pout = outbuf; <br /><br />…打开文件,读入GB2312数据到inbuf,数据长度为 len <br /><br />int inleft = len; <br />int outleft = BUFLEN; <br /><br />iconv_t cd; <br />if((cd = iconv_open(“gb2312”, “unicode”)) == (iconv_t)-1) <br />return –1; <br />if(iconv(cd, &amp;pin, &amp;inleft, &amp;pout, &amp;outleft) == (size_t)-1) <br />return –1; <br />iconv_close(cd); <br /><br />使用 iconv () 时,需要注意参数的使用,inleft 是输入缓冲区数据数据长度,outleft是输出缓冲区大小。(需要保证输出缓冲区足够大)。 <br />转换以后,outleft 是outbuf中空闲空间的大小,所以 BUFLEN-outleft 才是真正的Unicode数据长度。 <br />注意:不论是GB2312编码,还是Unicode编码,在内存中都是一些字节序列,所以我们可以统一用 类型为 char(或者unsigned char)的字符数组来保存。所以,BUFLEN-outleft 是 字符(char)个数,而不是Unicode字符个数。 <br /><br /><br />2、 Unicode 编码到 16-bit 编码的转换 <br /><br />在得到 Unicode编码以后,还需要转换到 PDU 的16-bit 编码,才可以正确的发送。在这个转换过程中,需要注意两点: <br />1)、Unicode 编码最开始的 0xFEFF标志要被去除,在0xFEFF之后的内容,才是真正的Unicode字符。(至于为什么有这个0xfeff标志,知道的朋友告诉我一声,呵呵)。 <br /><br />2)、Unicode 是双字节字符,由于我的系统是小端字节序(little-endian),也就是说,在存储的时候,是先低位,后高位,例如“中”的Unicode编码是 0x4E2D,存储的时候是 2D4E,在转换到 16-bit编码的时候,要注意这个顺序的不同。当然,如果你的系统是大端字节序(big-endian),那么就不用这样做了。 <br /><br />OK,关于如何将 0x4E2D 的Unicode编码转换到 “4E2D” 的16-bit编码,我就不多写了。 <br /><br /><br />3、正确计算16-bit 编码的消息体长度 <br /><br />4、正确设置 First-Octet 、TP-MR、TP-PID、TP-DCS、TP-VP <br /><br />在PDU格式中,First-Octet 、TP-MR、TP-PID、TP-DCS、TP-VP的设置正确与否,对能否发送 Unicode 至关重要。根据协议规范以及我的调试结果,以上几个标志的正确设置分别为(都是16进制): <br />First-Octet : 11 <br />TP-MR : 00 <br />TP-PID : 00 <br />TP-DCS : 08 (编码方式,16-bit) <br />TP-VP : A7 <br /><br />经过以上步骤,已经可以做到发送中文字符了。 <br />希望这篇文档,能为准备在linux下做短信开发的朋友提供一些帮助。 <br /><!--QuoteEnd--></div><!--QuoteEEnd-->

2005-8-26 09:51 99大话王
我想把<span style='color:red'>一</span>个汉字转unicode的代码,在Linux下不成功 <!--emo&:cry:--><img src='style_emoticons/default/cry_smile.gif' border='0' style='vertical-align:middle' alt='cry_smile.gif' /><!--endemo--> <br />iconv返回-1 <!--emo&:(--><img src='style_emoticons/default/sad.gif' border='0' style='vertical-align:middle' alt='sad.gif' /><!--endemo--> <br />谁有过这方面的经验,谢谢指点<br /><br /><!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->        wchar_t Gb2312ToUnicode&#40;char *pStr&#41;<br />        {<br /> &nbsp;static wchar_t wch = 0;<br /> &nbsp;wch = 0;<br />#ifdef        WIN32<br /> &nbsp;&#58;&#58;MultiByteToWideChar&#40;CP_ACP, MB_PRECOMPOSED, pStr, 2, &amp;wch, 1&#41;;<br />#else<br /> &nbsp;bool iconv_good = false;<br /> &nbsp;do<br /> &nbsp;{<br /> &nbsp;        iconv_t cd = iconv_open&#40;&#34;gb2312&#34;, &#34;unicode&#34;&#41;;<br /> &nbsp;        if &#40;0 == cd&#41;<br /> &nbsp;        {<br /> &nbsp; &nbsp;cout &#60;&#60; &#34;0 == iconv_open&#34; &#60;&#60; endl;<br /> &nbsp; &nbsp;break;<br /> &nbsp;        }<br /><br /> &nbsp;        char *pin = pStr;<br /> &nbsp;        size_t inlen = 2;<br /><br /> &nbsp;        char *outbuf = &#40;char*&#41;&amp;wch;<br /> &nbsp;        char *pout = outbuf;<br /> &nbsp;        size_t outlen = 2;<br /><br /> &nbsp;        char buf&#91;10&#93;;<br /> &nbsp;        outbuf = buf;<br /> &nbsp;        outlen = 10;<br /><br /> &nbsp;        if &#40;-1 == iconv&#40;cd, &amp;pin, &amp;inlen, &amp;pout, &amp;outlen&#41;&#41;<br /> &nbsp;        {<br /> &nbsp; &nbsp;cout &#60;&#60; &#34;-1 == iconv&#34; &#60;&#60; endl;<br /> &nbsp; &nbsp;break;<br /> &nbsp;        }<br /> &nbsp;        iconv_close&#40;cd&#41;;<br /> &nbsp;        iconv_good = true;<br /> &nbsp;}<br /> &nbsp;while &#40;false&#41;;<br /> &nbsp;if &#40;true &#33;= iconv_good&#41;<br /> &nbsp;{<br /> &nbsp;        cout &#60;&#60; &#34;iconv_good = &#34; &#60;&#60; iconv_good &#60;&#60; endl;<br /><br /> &nbsp;        /*<br /> &nbsp;        int ch = *pStr;<br /> &nbsp;        int ch2 = *&#40;pStr + 1&#41;;<br /> &nbsp;        int c = &#40; ch2 | &#40;ch &#60;&#60; 8&#41; &#41;;<br /> &nbsp;        wch = c;<br /> &nbsp;        */<br /> &nbsp;}<br />#endif<br /> &nbsp;cout &#60;&#60; &#34;wch = &#34; &#60;&#60; wch &#60;&#60; endl;<br /> &nbsp;return wch;<br />        }<br /><!--c2--></div><!--ec2-->

2005-8-26 10:14 wcp2004
学习中,不错!

2005-8-26 14:52 无双
unicode的iconv 参数应该是&quot;UCS-2&quot;吧 改下看看

2005-8-26 17:43 99大话王
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1--><br />// &amp;acute;ú&amp;Acirc;&amp;euml;×&amp;ordf;&amp;raquo;&amp;raquo;&amp;sup2;&amp;Ugrave;×÷&amp;Agrave;à<br />class CodeConverter<br />{<br />private&#58;<br />        iconv_t cd;<br />public&#58;<br />        // &amp;sup1;&amp;sup1;&amp;Ocirc;ì<br />        CodeConverter&#40;const char *from_charset,const char *to_charset&#41;<br />        {<br /> &nbsp;cd = iconv_open&#40;to_charset,from_charset&#41;;<br />        }<br />        <br />        // &amp;Icirc;&amp;ouml;&amp;sup1;&amp;sup1;<br />        ~CodeConverter&#40;&#41;<br />        {<br /> &nbsp;iconv_close&#40;cd&#41;;<br />        }<br />        <br />        // ×&amp;ordf;&amp;raquo;&amp;raquo;&amp;Ecirc;&amp;auml;&amp;sup3;&amp;ouml;<br />        int convert&#40;char *inbuf,int inlen,char *outbuf,int outlen&#41;<br />        {<br /> &nbsp;char **pin = &amp;inbuf;<br /> &nbsp;char **pout = &amp;outbuf;<br /> &nbsp;<br /> &nbsp;memset&#40;outbuf,0,outlen&#41;;<br /> &nbsp;//return iconv&#40;cd,pin,&#40;size_t *&#41;&amp;inlen,pout,&#40;size_t *&#41;&amp;outlen&#41;;<br /> &nbsp;int ret = iconv&#40;cd,pin,&#40;size_t *&#41;&amp;inlen,pout,&#40;size_t *&#41;&amp;outlen&#41;;<br /> &nbsp;if &#40;-1 == ret&#41; printf &#40;&#34;iconv&#58; %m\n&#34;&#41;;<br /> &nbsp;return ret;<br />        }<br />};<br /><!--c2--></div><!--ec2--><br />成功了<br />void main()<br />{<br />#define OUTLEN 255<br />        char* p1 = &quot;超级女生&quot;;<br />        char p2[] = {*p1, *(p1 + 1), 0};<br />        char out[OUTLEN];<br />        CodeConverter cc2 = CodeConverter(&quot;gb2312&quot;,&quot;unicode&quot;);<br />        int n = cc2.convert(p1, strlen(p1), out,OUTLEN);<br />}<br />

2005-8-29 09:30 无双
哦 原来你第一次传入的参数是指针地址 所以出问题

2006-9-30 13:20 triphop
如果想详细学习一下SMS的话,建议看看3GPP 24.011协议
不过从我个人角度来说,SMS协议应该是非常简单的协议。
从终端和短信中心的交互流程上讲,也是非常简单。
就是几个CP-DATA, CP-ACK

页: [1]


Powered by Discuz! Archiver 5.5.0  © 2001-2006 Comsenz Inc.